diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 61ab421f04..af69d26922 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,7 @@ env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release GTEST_REF: b85864c64758dec007208e56af933fc3f52044ee + ORTOOLS_VER: "9.8" jobs: build-on-ubuntu: @@ -27,7 +28,27 @@ jobs: echo "GTEST=$GTEST" >> $GITHUB_ENV SSCDIR=$GITHUB_WORKSPACE/ssc echo "SSCDIR=$SSCDIR" >> $GITHUB_ENV + ORTOOLSDIR=$GITHUB_WORKSPACE/or-tools + echo "ORTOOLSDIR=$ORTOOLSDIR" >> $GITHUB_ENV + - name: Get cached OR-Tools + uses: actions/cache@v4 + id: cachedortools + with: + path: ${{env.ORTOOLSDIR}}/ + key: ortools-ubuntu + + - name: Download OR-Tools + if: steps.cachedortools.outputs.cache-hit != 'true' + run: | + sudo apt update + sudo apt install -y build-essential cmake lsb-release + cd $GITHUB_WORKSPACE + wget -q https://github.com/google/or-tools/releases/download/v${ORTOOLS_VER}/or-tools_amd64_ubuntu-22.04_cpp_v${ORTOOLS_VER}.3296.tar.gz + tar -xvf or-tools_amd64_ubuntu-* + mkdir or-tools + mv or-tools*/* or-tools + - name: Get cached GTest uses: actions/cache@v4 id: cachedgtest @@ -51,7 +72,7 @@ jobs: cd ${GTEST}/build cmake -DCMAKE_CXX_FLAGS=-std=c++11 .. make - + - name: Checkout SSC uses: actions/checkout@v4 with: @@ -62,7 +83,7 @@ jobs: run: | mkdir ${SSCDIR}/build cd ${SSCDIR}/build - cmake .. -DCMAKE_BUILD_TYPE=Release -DSAM_SKIP_TOOLS=1 + cmake .. -DCMAKE_BUILD_TYPE=Release -DSAM_SKIP_TOOLS=1 -DCMAKE_INSTALL_PREFIX=${ORTOOLSDIR} - name: Build # Build your program with the given configuration @@ -78,7 +99,7 @@ jobs: ${SSCDIR}/build/test/Test - name: Upload Artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v2 with: name: SSC Linux Shared Libraries path: | @@ -105,13 +126,39 @@ jobs: echo "GTEST=$GTEST" >> $GITHUB_ENV SSCDIR=$GITHUB_WORKSPACE/ssc echo "SSCDIR=$SSCDIR" >> $GITHUB_ENV + ORTOOLSDIR=$GITHUB_WORKSPACE/or-tools + echo "ORTOOLSDIR=$ORTOOLSDIR" >> $GITHUB_ENV + - name: Get cached OR-Tools + uses: actions/cache@v4 + id: cachedortools + with: + path: ${{env.ORTOOLSDIR}}/ + key: ortools-${{ matrix.os }} + + - name: download OR-Tools for Arm64 + if: ${{ matrix.os == 'macos-latest' && steps.cachedortools.outputs.cache-hit != 'true'}} + run: | + cd $GITHUB_WORKSPACE + curl -LJO https://github.com/google/or-tools/releases/download/v${ORTOOLS_VER}/or-tools_arm64_macOS-14.1_cpp_v${ORTOOLS_VER}.3296.tar.gz + tar -xvf or-tools_arm64*.tar.gz + mkdir or-tools + mv or-tools*/* or-tools + - name: download OR-Tools for Intel + if: ${{ matrix.os == 'macos-14-large' && steps.cachedortools.outputs.cache-hit != 'true'}} + run: | + cd $GITHUB_WORKSPACE + curl -LJO https://github.com/google/or-tools/releases/download/v${ORTOOLS_VER}/or-tools_x86_64_macOS-14.1_cpp_v${ORTOOLS_VER}.3296.tar.gz + tar -xvf or-tools_x86_64*tar.gz + mkdir or-tools + mv or-tools*/* or-tools + - name: Get cached GTest uses: actions/cache@v4 id: cachedgtest with: path: ${{env.GTEST}}/ - key: gtest-${{ matrix.os }} + key: ortools-${{ matrix.os }} - name: Clone Gtest if: steps.cachedgtest.outputs.cache-hit != 'true' uses: actions/checkout@v4 @@ -139,7 +186,7 @@ jobs: run: | mkdir ${SSCDIR}/build cd ${SSCDIR}/build - cmake .. -DCMAKE_BUILD_TYPE=Release -DSAM_SKIP_TOOLS=1 -DSAMAPI_EXPORT=0 + cmake .. -DCMAKE_BUILD_TYPE=Release -DSAM_SKIP_TOOLS=1 -DSAMAPI_EXPORT=0 -DCMAKE_INSTALL_PREFIX=${ORTOOLSDIR} - name: Build # Build your program with the given configuration @@ -152,11 +199,11 @@ jobs: run: | set -e ${SSCDIR}/build/test/Test - shell: bash + shell: bash - name: Upload Artifacts if: ${{ matrix.os == 'macos-latest' }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v2 with: name: SSC Mac Arm Shared Libraries path: | @@ -165,7 +212,7 @@ jobs: - name: Upload Artifacts if: ${{ matrix.os != 'macos-latest' }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v2 with: name: SSC Mac Intel Shared Libraries path: | @@ -173,7 +220,7 @@ jobs: ${{env.SSCDIR}}/build/ssc/ssc.dylib build-on-windows: - runs-on: windows-2019 + runs-on: windows-latest steps: - name: Setup cmake @@ -190,7 +237,25 @@ jobs: echo "GTEST=$GTEST" >> $GITHUB_ENV SSCDIR=$GITHUB_WORKSPACE/ssc echo "SSCDIR=$SSCDIR" >> $GITHUB_ENV - + ORTOOLSDIR=$GITHUB_WORKSPACE/or-tools/install + echo "ORTOOLSDIR=$ORTOOLSDIR" >> $GITHUB_ENV + + - name: Get cached OR-Tools + uses: actions/cache@v4 + id: cachedortools + with: + path: ${{env.ORTOOLSDIR}} + key: ortools-windows + + - name: Download OR-Tools + if: steps.cachedortools.outputs.cache-hit != 'true' + shell: bash + run: | + cd $GITHUB_WORKSPACE + curl -LJO https://github.com/google/or-tools/releases/download/v${ORTOOLS_VER}/or-tools_x64_VisualStudio2022_cpp_v${ORTOOLS_VER}.3296.zip + unzip or-tools_x64_VisualStudio2022_cpp_* -d or-tools + mv or-tools/or-tools_* $ORTOOLSDIR + - name: Get cached GTest uses: actions/cache@v4 id: cachedgtest @@ -210,7 +275,6 @@ jobs: if: steps.cachedgtest.outputs.cache-hit != 'true' shell: bash run: | - export mkdir ${GTEST}/build cd ${GTEST}/build cmake -Dgtest_force_shared_crt=ON .. @@ -221,19 +285,18 @@ jobs: with: path: ssc - - name: Configure CMake + - name: Build SSC shell: bash - # Configure cmake to build ssc tests but not tools run: | - mkdir ${SSCDIR}/build - cd ${SSCDIR}/build - cmake .. -DSAM_SKIP_TOOLS=1 -DCMAKE_CONFIGURATION_TYPES="Release" - cmake --build . --config Release -j4 + # Downloaded OR-Tools has CoinOR enabled + mkdir $SSCDIR/build + cd $SSCDIR/build + cmake .. -DSAM_SKIP_TOOLS=1 -DCMAKE_CONFIGURATION_TYPES="Release" -DCMAKE_SYSTEM_VERSION="10.0" -DCMAKE_GENERATOR_PLATFORM=x64 -DUSE_COINOR=1 -DCMAKE_GENERATOR_PLATFORM=x64 -DUSE_COINOR=1 + cmake --build . --config Release -j4 --target Test cp ssc/Release/* test/Release - name: Test shell: bash - # Turn off fast fail for when the landbosse tests write to cerr run: | cd ${SSCDIR}/build/test/Release ./Test.exe diff --git a/.gitignore b/.gitignore index defbddc53a..a884909304 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,8 @@ bld/ build/ cmake-build-debug/ cmake-build-release/ +CMakeFiles +CMakeCache.txt test/Test # Visual Studio 2015 cache/options directory @@ -344,6 +346,7 @@ build_osx/Test build_linux/Test build_linux/config.status linux_test\.txt +build2 nlopt/config.h nlopt/config.status @@ -360,3 +363,5 @@ ssc/ssc\.exp ssc/sscd\.exp build_android/lib_oldssc.zip + +or-tools diff --git a/CMakeLists.txt b/CMakeLists.txt index 40886ced82..8fb64eac6a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,18 @@ option(SAM_SKIP_TESTS "Skips building tests" OFF) option(SAMAPI_EXPORT "Export of ssc binaries to the SAM_api directory; for Unix, compile ssc libraries for SAM_api" ON) +include(CMakeDependentOption) + +CMAKE_DEPENDENT_OPTION(BUILD_DEPS "Build OR-Tools dependencies" ON "NOT SKIP_ORTOOLS" OFF) +CMAKE_DEPENDENT_OPTION(USE_COINOR "Use the COIN-OR solver" OFF "NOT SKIP_ORTOOLS" OFF) +CMAKE_DEPENDENT_OPTION(USE_HIGHS "Use the HiGHS solver" OFF "NOT SKIP_ORTOOLS" OFF) +CMAKE_DEPENDENT_OPTION(BUILD_EXAMPLES "Build examples" OFF "NOT SKIP_ORTOOLS" OFF) +CMAKE_DEPENDENT_OPTION(BUILD_SAMPLES "Build samples" OFF "NOT SKIP_ORTOOLS" OFF) +CMAKE_DEPENDENT_OPTION(INSTALL_DOC "Install doc" OFF "NOT SKIP_ORTOOLS" OFF) +CMAKE_DEPENDENT_OPTION(USE_COINOR "Use COINOR solvers" OFF "NOT SKIP_ORTOOLS" OFF) +CMAKE_DEPENDENT_OPTION(USE_XPRESS "Adds support for the XPRESS Solver" OFF "NOT SKIP_ORTOOLS" OFF) + + # # If project isn't system_advisor_model and SAM_SKIP_TOOLS=1, # environment vars LK_LIB and LKD_LIB can be used to specify where to find those libraries @@ -26,10 +38,10 @@ if(APPLE) endif() if (UNIX AND NOT CMAKE_C_COMPILER) - set(CMAKE_C_COMPILER gcc) - set(CMAKE_CXX_COMPILER g++) + set(CMAKE_C_COMPILER gcc) + set(CMAKE_CXX_COMPILER g++) endif() -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 20) if ( NOT APPLE) set(CURL_DIR build_resources/libcurl_ssl_x64) @@ -45,7 +57,6 @@ Project(sam_simulation_core VERSION 1.0.0) ##################################################################################################################### set(CMAKE_VERBOSE_MAKEFILE ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) -set(CMAKE_CXX_STANDARD 11) function(set_no_warnings target) get_target_property(MAIN_CFLAGS ${target} COMPILE_FLAGS) @@ -82,6 +93,8 @@ function(set_default_compile_options target) set(MAIN_CFLAGS "") endif() set(MAIN_CFLAGS "${MAIN_CFLAGS} -D__64BIT__") + set_property(TARGET ${target} PROPERTY CXX_STANDARD 20) + set_property(TARGET ${target} PROPERTY CXX_STANDARD_REQUIRED ON) if(MSVC) set(MAIN_CFLAGS "${MAIN_CFLAGS} /bigobj /MP") set(MAIN_CFLAGS "${MAIN_CFLAGS} /D__WINDOWS__ /D_WINDOWS /D_CRT_SECURE_NO_WARNINGS /DLPWINAPP") @@ -89,7 +102,6 @@ function(set_default_compile_options target) set(${flag_var} "${${flag_var}} /D_DEBUG" CACHE STRING "compile flags" FORCE) endforeach() else(MSVC) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") if (APPLE) set(MAIN_CFLAGS "${MAIN_CFLAGS} -fno-common -DWX_PRECOMP -D__MACOSX__") else() @@ -119,7 +131,7 @@ function(set_tools_compile_options target) if (APPLE) set(MAIN_CFLAGS "${MAIN_CFLAGS} -D__WXOSX__") endif() - set(MAIN_CFLAGS "${MAIN_CFLAGS} -Wall -Wno-deprecated -Wno-unknown-pragmas -Wno-overloaded-virtual -fno-common -std=c++11") + set(MAIN_CFLAGS "${MAIN_CFLAGS} -Wall -Wno-deprecated -Wno-unknown-pragmas -Wno-overloaded-virtual -fno-common") set(MAIN_CFLAGS "${MAIN_CFLAGS} -DLK_USE_WXWIDGETS") endif(MSVC) set_target_properties(${target} PROPERTIES COMPILE_FLAGS ${MAIN_CFLAGS}) @@ -150,9 +162,9 @@ add_subdirectory(tcs) add_subdirectory(ssc) if (NOT SAM_SKIP_TOOLS) - add_subdirectory(sdktool) + add_subdirectory(sdktool) endif() if (NOT SAM_SKIP_TESTS) - add_subdirectory(test) + add_subdirectory(test) endif() diff --git a/code_attic/cmod_tcstrough_physical_csp_solver.cpp b/code_attic/cmod_tcstrough_physical_csp_solver.cpp index 3efbaf9a93..f3e294433e 100644 --- a/code_attic/cmod_tcstrough_physical_csp_solver.cpp +++ b/code_attic/cmod_tcstrough_physical_csp_solver.cpp @@ -30,6 +30,8 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define _HAS_STD_BYTE 0 + // Trough CSP - physical model #include "core.h" #include "tckernel.h" diff --git a/code_attic/cmod_trough_physical_iph_old.cpp b/code_attic/cmod_trough_physical_iph_old.cpp index f4172b1664..225081cd79 100644 --- a/code_attic/cmod_trough_physical_iph_old.cpp +++ b/code_attic/cmod_trough_physical_iph_old.cpp @@ -30,6 +30,8 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define _HAS_STD_BYTE 0 + // Trough CSP - physical model #include "core.h" //#include "tckernel.h" diff --git a/lpsolve/commonlib.cpp b/lpsolve/commonlib.cpp index 44727144fc..8d5b8335a7 100644 --- a/lpsolve/commonlib.cpp +++ b/lpsolve/commonlib.cpp @@ -381,8 +381,8 @@ int CMP_CALLMODEL compareREAL(const void *current, const void *candidate) where interchanges are reflected in a caller-initialized integer "tags" list. */ void hpsort(void *attributes, int count, int offset, int recsize, MYBOOL descending, findCompare_func findCompare) { - register int i, j, k, ir, order; - register char *hold, *base; + int i, j, k, ir, order; + char *hold, *base; char *save; if(count < 2) @@ -443,8 +443,8 @@ void hpsortex(void *attributes, int count, int offset, int recsize, MYBOOL desce return; } else { - register int i, j, k, ir, order; - register char *hold, *base; + int i, j, k, ir, order; + char *hold, *base; char *save; int savetag; @@ -528,7 +528,7 @@ void qsortex_swap(void *attributes, int l, int r, int recsize, int qsortex_sort(void *attributes, int l, int r, int recsize, int sortorder, findCompare_func findCompare, void *tags, int tagsize, char *save, char *savetag) { - register int i, j, nmove = 0; + int i, j, nmove = 0; char *v; /* Perform the a fast QuickSort */ @@ -667,7 +667,7 @@ void QS_delete(UNIONTYPE QSORTrec a[], int ipos, int epos) } int QS_sort(UNIONTYPE QSORTrec a[], int l, int r, findCompare_func findCompare) { - register int i, j, nmove = 0; + int i, j, nmove = 0; UNIONTYPE QSORTrec v; /* Perform the a fast QuickSort */ diff --git a/lpsolve/lp_BFP2.cpp b/lpsolve/lp_BFP2.cpp index 982f54c7ea..f9bdc0a3c8 100644 --- a/lpsolve/lp_BFP2.cpp +++ b/lpsolve/lp_BFP2.cpp @@ -158,9 +158,9 @@ REAL BFP_CALLMODEL bfp_pivotRHS(lprec *lp, LREAL theta, REAL *pcol) pcol = lu->pcol; if(theta != 0) { - register int i, n = lp->rows; - register LREAL roundzero = lp->epsvalue; - register LREAL *rhs = lp->rhs, rhsmax = 0; + int i, n = lp->rows; + LREAL roundzero = lp->epsvalue; + LREAL *rhs = lp->rhs, rhsmax = 0; for(i = 0; i <= n; i++, rhs++, pcol++) { (*rhs) -= theta * (*pcol); diff --git a/lpsolve/lp_lib.cpp b/lpsolve/lp_lib.cpp index 8b6bf99b0a..103ddde83c 100644 --- a/lpsolve/lp_lib.cpp +++ b/lpsolve/lp_lib.cpp @@ -172,7 +172,7 @@ void __WINAPI set_outputstream(lprec *lp, FILE *stream) lp->streamowned = FALSE; } -MYBOOL __WINAPI set_outputfile(lprec *lp, char *filename) +MYBOOL __WINAPI set_outputfile(lprec *lp, const char *filename) { MYBOOL ok; FILE *output = stdout; @@ -5720,12 +5720,12 @@ STATIC int get_basisOF(lprec *lp, int coltarget[], REAL crow[], int colno[]) { int i, n = lp->rows, nz = 0; REAL *obj = lp->obj; - register REAL epsvalue = lp->epsvalue; + REAL epsvalue = lp->epsvalue; /* Compute offset over the specified objective indeces (step 2) */ if(coltarget != NULL) { - register int ix, m = coltarget[0]; - register REAL value; + int ix, m = coltarget[0]; + REAL value; for(i = 1, coltarget++; i <= m; i++, coltarget++) { ix = *coltarget; @@ -5748,7 +5748,7 @@ STATIC int get_basisOF(lprec *lp, int coltarget[], REAL crow[], int colno[]) /* Get the basic objective function values (step 1) */ else { - register int *basvar = lp->var_basic; + int *basvar = lp->var_basic; for(i = 1, crow++, basvar++; i <= n; i++, crow++, basvar++) { @@ -8005,7 +8005,7 @@ STATIC int compute_theta(lprec *lp, int rownr, LREAL *theta, int isupbound, REAL the leaving variable. Note that the incoming theta is "d" in Chvatal-terminology */ { int colnr = lp->var_basic[rownr]; - register LREAL x = lp->rhs[rownr]; + LREAL x = lp->rhs[rownr]; REAL lb = 0, /* Put lower bound here when the fully bounded version is implemented */ ub = lp->upbo[colnr], eps = lp->epsprimal; /* Primal feasibility tolerance */ diff --git a/lpsolve/lp_lib.h b/lpsolve/lp_lib.h index 7269d365f5..ad6e71005a 100644 --- a/lpsolve/lp_lib.h +++ b/lpsolve/lp_lib.h @@ -1032,7 +1032,7 @@ typedef void (__WINAPI set_obj_bound_func)(lprec *lp, REAL obj_bound); typedef MYBOOL (__WINAPI set_obj_fn_func)(lprec *lp, REAL *row); typedef MYBOOL (__WINAPI set_obj_fnex_func)(lprec *lp, int count, REAL *row, int *colno); typedef void (__WINAPI set_obj_in_basis_func)(lprec *lp, MYBOOL obj_in_basis); -typedef MYBOOL (__WINAPI set_outputfile_func)(lprec *lp, char *filename); +typedef MYBOOL (__WINAPI set_outputfile_func)(lprec *lp, const char *filename); typedef void (__WINAPI set_outputstream_func)(lprec *lp, FILE *stream); typedef MYBOOL (__WINAPI set_partialprice_func)(lprec *lp, int blockcount, int *blockstart, MYBOOL isrow); typedef void (__WINAPI set_pivoting_func)(lprec *lp, int piv_rule); @@ -2000,7 +2000,7 @@ void __EXPORT_TYPE __WINAPI print_scales(lprec *lp); void __EXPORT_TYPE __WINAPI print_str(lprec *lp, char *str); void __EXPORT_TYPE __WINAPI set_outputstream(lprec *lp, FILE *stream); -MYBOOL __EXPORT_TYPE __WINAPI set_outputfile(lprec *lp, char *filename); +MYBOOL __EXPORT_TYPE __WINAPI set_outputfile(lprec *lp, const char *filename); void __EXPORT_TYPE __WINAPI set_verbose(lprec *lp, int verbose); int __EXPORT_TYPE __WINAPI get_verbose(lprec *lp); diff --git a/lpsolve/lp_matrix.cpp b/lpsolve/lp_matrix.cpp index f746d29668..aff532a902 100644 --- a/lpsolve/lp_matrix.cpp +++ b/lpsolve/lp_matrix.cpp @@ -2279,8 +2279,8 @@ STATIC void mat_multcol(MATrec *mat, int col_nr, REAL mult, MYBOOL DoObj) STATIC void mat_multadd(MATrec *mat, REAL *lhsvector, int varnr, REAL mult) { int colnr; - register int ib, ie, *matRownr; - register REAL *matValue; + int ib, ie, *matRownr; + REAL *matValue; /* Handle case of a slack variable */ if(varnr <= mat->lp->rows) { @@ -3405,11 +3405,11 @@ STATIC int prod_xA(lprec *lp, int *coltarget, int colnr, rownr, varnr, ib, ie, vb, ve, nrows = lp->rows; MYBOOL localset, localnz = FALSE, includeOF, isRC; REALXP vmax; - register REALXP v; + REALXP v; int inz, *rowin, countNZ = 0; MATrec *mat = lp->matA; - register REAL *matValue; - register int *matRownr; + REAL *matValue; + int *matRownr; /* Clean output area (only necessary if we are returning the full vector) */ isRC = (MYBOOL) ((roundmode & MAT_ROUNDRC) != 0); @@ -3617,11 +3617,11 @@ STATIC MYBOOL prod_xA2(lprec *lp, int *coltarget, int varnr, colnr, ib, ie, vb, ve, nrows = lp->rows; MYBOOL includeOF, isRC; REALXP dmax, pmax; - register REALXP d, p; + REALXP d, p; MATrec *mat = lp->matA; REAL value; - register REAL *matValue; - register int *matRownr; + REAL *matValue; + int *matRownr; MYBOOL localset; /* Find what variable range to scan - default is {SCAN_USERVARS} */ diff --git a/lpsolve/lp_params.cpp b/lpsolve/lp_params.cpp index f34f28c909..a90b00bc35 100644 --- a/lpsolve/lp_params.cpp +++ b/lpsolve/lp_params.cpp @@ -276,22 +276,22 @@ static struct _values verbose[] = static struct _functions functions[] = { /* solve options */ - { "ANTI_DEGEN", setintfunction(get_anti_degen, set_anti_degen), setvalues(anti_degen, ~0), WRITE_ACTIVE }, - { "BASISCRASH", setintfunction(get_basiscrash, set_basiscrash), setvalues(basiscrash, ~0), WRITE_ACTIVE }, - { "IMPROVE", setintfunction(get_improve, set_improve), setvalues(improve, ~0), WRITE_ACTIVE }, + { "ANTI_DEGEN", setintfunction(get_anti_degen, set_anti_degen), setvalues(anti_degen, static_cast(~0)), WRITE_ACTIVE }, + { "BASISCRASH", setintfunction(get_basiscrash, set_basiscrash), setvalues(basiscrash, static_cast(~0)), WRITE_ACTIVE }, + { "IMPROVE", setintfunction(get_improve, set_improve), setvalues(improve, static_cast(~0)), WRITE_ACTIVE }, { "MAXPIVOT", setintfunction(get_maxpivot, set_maxpivot), setNULLvalues, WRITE_ACTIVE }, { "NEGRANGE", setREALfunction(get_negrange, set_negrange), setNULLvalues, WRITE_ACTIVE }, { "PIVOTING", setintfunction(get_pivoting, set_pivoting), setvalues(pivoting, PRICER_LASTOPTION), WRITE_ACTIVE }, - { "PRESOLVE", setintfunction(get_presolve, set_presolve1), setvalues(presolving, ~0), WRITE_ACTIVE }, + { "PRESOLVE", setintfunction(get_presolve, set_presolve1), setvalues(presolving, static_cast(~0)), WRITE_ACTIVE }, { "PRESOLVELOOPS", setintfunction(get_presolveloops, set_presolve2), setNULLvalues, WRITE_ACTIVE }, { "SCALELIMIT", setREALfunction(get_scalelimit, set_scalelimit), setNULLvalues, WRITE_ACTIVE }, { "SCALING", setintfunction(get_scaling, set_scaling), setvalues(scaling, SCALE_CURTISREID), WRITE_ACTIVE }, - { "SIMPLEXTYPE", setintfunction(get_simplextype, set_simplextype), setvalues(simplextype, ~0), WRITE_ACTIVE }, + { "SIMPLEXTYPE", setintfunction(get_simplextype, set_simplextype), setvalues(simplextype, static_cast(~0)), WRITE_ACTIVE }, { "OBJ_IN_BASIS", setMYBOOLfunction(is_obj_in_basis, set_obj_in_basis), setNULLvalues, WRITE_COMMENTED }, /* B&B options */ { "BB_DEPTHLIMIT", setintfunction(get_bb_depthlimit, set_bb_depthlimit), setNULLvalues, WRITE_ACTIVE }, - { "BB_FLOORFIRST", setintfunction(get_bb_floorfirst, set_bb_floorfirst), setvalues(bb_floorfirst, ~0), WRITE_ACTIVE }, + { "BB_FLOORFIRST", setintfunction(get_bb_floorfirst, set_bb_floorfirst), setvalues(bb_floorfirst, static_cast(~0)), WRITE_ACTIVE }, { "BB_RULE", setintfunction(get_bb_rule, set_bb_rule), setvalues(bb_rule, NODE_STRATEGYMASK), WRITE_ACTIVE }, { "BREAK_AT_FIRST", setMYBOOLfunction(is_break_at_first, set_break_at_first), setNULLvalues, WRITE_COMMENTED }, { "BREAK_AT_VALUE", setREALfunction(get_break_at_value, set_break_at_value), setNULLvalues, WRITE_COMMENTED }, @@ -310,10 +310,10 @@ static struct _functions functions[] = /* read-only options */ { "DEBUG", setMYBOOLfunction(is_debug, set_debug), setNULLvalues, WRITE_COMMENTED }, { "OBJ_BOUND", setREALfunction(get_obj_bound, set_obj_bound), setNULLvalues, WRITE_COMMENTED }, - { "PRINT_SOL", setintfunction(get_print_sol, set_print_sol), setvalues(print_sol, ~0), WRITE_COMMENTED }, + { "PRINT_SOL", setintfunction(get_print_sol, set_print_sol), setvalues(print_sol, static_cast(~0)), WRITE_COMMENTED }, { "TIMEOUT", setlongfunction(get_timeout, set_timeout), setNULLvalues, WRITE_COMMENTED }, { "TRACE", setMYBOOLfunction(is_trace, set_trace), setNULLvalues, WRITE_COMMENTED }, - { "VERBOSE", setintfunction(get_verbose, set_verbose), setvalues(verbose, ~0), WRITE_COMMENTED }, + { "VERBOSE", setintfunction(get_verbose, set_verbose), setvalues(verbose, static_cast(~0)), WRITE_COMMENTED }, }; static void write_params1(lprec *lp, FILE *fp, char *header, int newline) diff --git a/lpsolve/lp_price.cpp b/lpsolve/lp_price.cpp index 76a261775c..ba2b2be93b 100644 --- a/lpsolve/lp_price.cpp +++ b/lpsolve/lp_price.cpp @@ -52,9 +52,9 @@ The original version of lp_solve can be found at https://sourceforge.net/project dual simplexes. The functions compare a candidate variable with an incumbent. */ int CMP_CALLMODEL compareImprovementVar(const pricerec *current, const pricerec *candidate) { - register int result = COMP_PREFERNONE; - register lprec *lp = current->lp; - register REAL testvalue, margin = PREC_IMPROVEGAP; + int result = COMP_PREFERNONE; + lprec *lp = current->lp; + REAL testvalue, margin = PREC_IMPROVEGAP; int currentcolno, currentvarno = current->varno, candidatecolno, candidatevarno = candidate->varno; MYBOOL isdual = candidate->isdual; @@ -163,9 +163,9 @@ int CMP_CALLMODEL compareImprovementVar(const pricerec *current, const pricerec int CMP_CALLMODEL compareSubstitutionVar(const pricerec *current, const pricerec *candidate) { - register int result = COMP_PREFERNONE; - register lprec *lp = current->lp; - register REAL testvalue = candidate->theta, + int result = COMP_PREFERNONE; + lprec *lp = current->lp; + REAL testvalue = candidate->theta, margin = current->theta; MYBOOL isdual = candidate->isdual, candbetter; int currentcolno, currentvarno = current->varno, @@ -303,9 +303,9 @@ int CMP_CALLMODEL compareSubstitutionVar(const pricerec *current, const pricerec } int CMP_CALLMODEL compareBoundFlipVar(const pricerec *current, const pricerec *candidate) { - register REAL testvalue, margin; - register int result = COMP_PREFERNONE; - register lprec *lp = current->lp; + REAL testvalue, margin; + int result = COMP_PREFERNONE; + lprec *lp = current->lp; MYBOOL candbetter; int currentvarno = current->varno, candidatevarno = candidate->varno; @@ -383,7 +383,7 @@ int CMP_CALLMODEL compareBoundFlipVar(const pricerec *current, const pricerec *c a subject for the comparison functions/operators. */ STATIC MYBOOL validImprovementVar(pricerec *candidate) { - register REAL candidatepivot = std::fabs(candidate->pivot); + REAL candidatepivot = std::fabs(candidate->pivot); #ifdef Paranoia return( (MYBOOL) ((candidate->varno > 0) && (candidatepivot > candidate->lp->epsvalue)) ); @@ -394,8 +394,8 @@ STATIC MYBOOL validImprovementVar(pricerec *candidate) STATIC MYBOOL validSubstitutionVar(pricerec *candidate) { - register lprec *lp = candidate->lp; - register REAL theta = (candidate->isdual ? std::fabs(candidate->theta) : candidate->theta); + lprec *lp = candidate->lp; + REAL theta = (candidate->isdual ? std::fabs(candidate->theta) : candidate->theta); #ifdef Paranoia if(candidate->varno <= 0) @@ -1179,7 +1179,7 @@ STATIC int rowprim(lprec *lp, int colnr, LREAL *theta, REAL *pcol, int *nzpcol, STATIC int rowdual(lprec *lp, REAL *rhvec, MYBOOL forceoutEQ, MYBOOL updateinfeas, REAL *xviol) { int k, i, iy, iz, ii, ninfeas; - register REAL rh; + REAL rh; REAL up, lo = 0, epsvalue, sinfeas, xinfeas; pricerec current, candidate; diff --git a/lpsolve/lp_rlp.h b/lpsolve/lp_rlp.h index 4f7e548702..22dc2bd783 100644 --- a/lpsolve/lp_rlp.h +++ b/lpsolve/lp_rlp.h @@ -189,7 +189,7 @@ typedef struct lp_yy_buffer_state *YY_BUFFER_STATE; * existing scanners that call lp_yyless() from OUTSIDE lp_yylex. * One obvious solution it to make lp_yy_act a global. I tried that, and saw * a 5% performance hit in a non-lp_yylineno scanner, because lp_yy_act is - * normally declared as a register variable-- so it is not worth it. + * normally declared as a variable-- so it is not worth it. */ #define YY_LESS_LINENO(n) \ do { \ @@ -842,9 +842,9 @@ extern int lp_yylex \ */ YY_DECL { - register lp_yy_state_type lp_yy_current_state; - register char *lp_yy_cp, *lp_yy_bp; - register int lp_yy_act; + lp_yy_state_type lp_yy_current_state; + char *lp_yy_cp, *lp_yy_bp; + int lp_yy_act; struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; lp_yylval = lp_yylval_param; @@ -892,7 +892,7 @@ YY_DECL lp_yy_match: do { - register YY_CHAR lp_yy_c = lp_yy_ec[YY_SC_TO_UI(*lp_yy_cp)]; + YY_CHAR lp_yy_c = lp_yy_ec[YY_SC_TO_UI(*lp_yy_cp)]; if ( lp_yy_accept[lp_yy_current_state] ) { lp_yyg->lp_yy_last_accepting_state = lp_yy_current_state; @@ -1425,9 +1425,9 @@ case YY_STATE_EOF(LINECOMMENT): static int lp_yy_get_next_buffer (lp_yyscan_t lp_yyscanner) { struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; - register char *dest = YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf; - register char *source = lp_yyg->lp_yytext_ptr; - register int number_to_move, i; + char *dest = YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf; + char *source = lp_yyg->lp_yytext_ptr; + int number_to_move, i; int ret_val; if ( lp_yyg->lp_yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf[lp_yyg->lp_yy_n_chars + 1] ) @@ -1559,8 +1559,8 @@ static int lp_yy_get_next_buffer (lp_yyscan_t lp_yyscanner) static lp_yy_state_type lp_yy_get_previous_state (lp_yyscan_t lp_yyscanner) { - register lp_yy_state_type lp_yy_current_state; - register char *lp_yy_cp; + lp_yy_state_type lp_yy_current_state; + char *lp_yy_cp; struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; lp_yy_current_state = lp_yyg->lp_yy_start; @@ -1568,7 +1568,7 @@ static int lp_yy_get_next_buffer (lp_yyscan_t lp_yyscanner) for ( lp_yy_cp = lp_yyg->lp_yytext_ptr + YY_MORE_ADJ; lp_yy_cp < lp_yyg->lp_yy_c_buf_p; ++lp_yy_cp ) { - register YY_CHAR lp_yy_c = (*lp_yy_cp ? lp_yy_ec[YY_SC_TO_UI(*lp_yy_cp)] : 1); + YY_CHAR lp_yy_c = (*lp_yy_cp ? lp_yy_ec[YY_SC_TO_UI(*lp_yy_cp)] : 1); if ( lp_yy_accept[lp_yy_current_state] ) { lp_yyg->lp_yy_last_accepting_state = lp_yy_current_state; @@ -1593,11 +1593,11 @@ static int lp_yy_get_next_buffer (lp_yyscan_t lp_yyscanner) */ static lp_yy_state_type lp_yy_try_NUL_trans (lp_yy_state_type lp_yy_current_state , lp_yyscan_t lp_yyscanner) { - register int lp_yy_is_jam; + int lp_yy_is_jam; struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; /* This var may be unused depending upon options. */ - register char *lp_yy_cp = lp_yyg->lp_yy_c_buf_p; + char *lp_yy_cp = lp_yyg->lp_yy_c_buf_p; - register YY_CHAR lp_yy_c = 1; + YY_CHAR lp_yy_c = 1; if ( lp_yy_accept[lp_yy_current_state] ) { lp_yyg->lp_yy_last_accepting_state = lp_yy_current_state; @@ -1615,9 +1615,9 @@ static int lp_yy_get_next_buffer (lp_yyscan_t lp_yyscanner) return lp_yy_is_jam ? 0 : lp_yy_current_state; } - static void lp_yyunput (int c, register char * lp_yy_bp , lp_yyscan_t lp_yyscanner) + static void lp_yyunput (int c, char * lp_yy_bp , lp_yyscan_t lp_yyscanner) { - register char *lp_yy_cp; + char *lp_yy_cp; struct lp_yyguts_t * lp_yyg = (struct lp_yyguts_t*)lp_yyscanner; lp_yy_cp = lp_yyg->lp_yy_c_buf_p; @@ -1628,10 +1628,10 @@ static int lp_yy_get_next_buffer (lp_yyscan_t lp_yyscanner) if ( lp_yy_cp < YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ - register int number_to_move = lp_yyg->lp_yy_n_chars + 2; - register char *dest = &YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf[ + int number_to_move = lp_yyg->lp_yy_n_chars + 2; + char *dest = &YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->lp_yy_buf_size + 2]; - register char *source = + char *source = &YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf[number_to_move]; while ( source > YY_CURRENT_BUFFER_LVALUE->lp_yy_ch_buf ) @@ -2421,7 +2421,7 @@ int lp_yylex_destroy (lp_yyscan_t lp_yyscanner) #ifndef lp_yytext_ptr static void lp_yy_flex_strncpy (char* s1, lp_yyconst char * s2, int n , lp_yyscan_t lp_yyscanner) { - register int i; + int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } @@ -2430,7 +2430,7 @@ static void lp_yy_flex_strncpy (char* s1, lp_yyconst char * s2, int n , lp_yysca #ifdef YY_NEED_STRLEN static int lp_yy_flex_strlen (lp_yyconst char * s , lp_yyscan_t lp_yyscanner) { - register int n; + int n; for ( n = 0; s[n]; ++n ) ; diff --git a/lpsolve/lp_scale.cpp b/lpsolve/lp_scale.cpp index 1fee530c3e..04bfed783d 100644 --- a/lpsolve/lp_scale.cpp +++ b/lpsolve/lp_scale.cpp @@ -93,7 +93,7 @@ REAL CurtisReidMeasure(lprec *lp, MYBOOL _Advanced, REAL *FRowScale, REAL *FColS { int i, nz; REAL absvalue, logvalue; - register REAL result; + REAL result; MATrec *mat = lp->matA; REAL *value; int *rownr, *colnr; diff --git a/lpsolve/lp_utils.cpp b/lpsolve/lp_utils.cpp index 1eb9aa8e53..c23732b0f8 100644 --- a/lpsolve/lp_utils.cpp +++ b/lpsolve/lp_utils.cpp @@ -966,7 +966,7 @@ STATIC MYBOOL verifyLink(LLrec *linkmap, int itemnr, MYBOOL doappend) STATIC PVrec *createPackedVector(int size, REAL *values, int *workvector) { int i, k; - REGISTER REAL ref; + REAL ref; PVrec *newPV = NULL; MYBOOL localWV = (MYBOOL) (workvector == NULL); @@ -1013,7 +1013,7 @@ STATIC PVrec *createPackedVector(int size, REAL *values, int *workvector) STATIC MYBOOL unpackPackedVector(PVrec *PV, REAL **target) { int i, ii, k; - REGISTER REAL ref; + REAL ref; /* Test for validity of the target and create it if necessary */ if(target == NULL) diff --git a/lpsolve/lusol1.cpp b/lpsolve/lusol1.cpp index 0741efd4af..e4859fa9f7 100644 --- a/lpsolve/lusol1.cpp +++ b/lpsolve/lusol1.cpp @@ -49,12 +49,12 @@ void LU1DCP(LUSOLrec *LUSOL, REAL DA[], int LDA, int M, int N, REAL SMALL, int I, J, K, KP1, L, LAST, LENCOL, IMAX, JMAX, JLAST, JNEW; REAL AIJMAX, AJMAX; - register REAL T; + REAL T; #ifdef LUSOLFastDenseIndex - register REAL *DA1, *DA2; + REAL *DA1, *DA2; int IDA1, IDA2; #else - register int IDA1, IDA2; + int IDA1, IDA2; #endif *NSING = 0; @@ -241,12 +241,12 @@ void LU1DPP(LUSOLrec *LUSOL, REAL DA[], int LDA, int M, int N, REAL SMALL, int *NSING, int IPVT[], int IX[]) { int I, J, K, KP1, L, LAST, LENCOL; - register REAL T; + REAL T; #ifdef LUSOLFastDenseIndex - register REAL *DA1, *DA2; + REAL *DA1, *DA2; int IDA1, IDA2; #else - register int IDA1, IDA2; + int IDA1, IDA2; #endif *NSING = 0; @@ -679,7 +679,7 @@ void LU1GAU(LUSOLrec *LUSOL, int MELIM, int NSPARE, MYBOOL ATEND; int LR, J, LENJ, NFREE, LC1, LC2, NDONE, NDROP, L, I, LL, K, LR1, LAST, LREP, L1, L2, LC, LENI; - register REAL UJ; + REAL UJ; REAL AIJ; for(LR = *LFIRST; LR <= LPIVR2; LR++) { diff --git a/lpsolve/lusol6a.cpp b/lpsolve/lusol6a.cpp index fca4b28432..ceaf203bff 100644 --- a/lpsolve/lusol6a.cpp +++ b/lpsolve/lusol6a.cpp @@ -367,7 +367,7 @@ void LU6L(LUSOLrec *LUSOL, int *INFORM, REAL V[], int NZidx[]) { int JPIV, K, L, L1, LEN, LENL, LENL0, NUML, NUML0; REAL SMALL; - register REAL VPIV; + REAL VPIV; #ifdef LUSOLFastSolve REAL *aptr; int *iptr, *jptr; @@ -459,7 +459,7 @@ void LU6LD(LUSOLrec *LUSOL, int *INFORM, int MODE, REAL V[], int NZidx[]) { int IPIV, K, L, L1, LEN, NUML0; REAL DIAG, SMALL; - register REAL VPIV; + REAL VPIV; #ifdef LUSOLFastSolve REAL *aptr; int *jptr; @@ -523,8 +523,8 @@ void LU6LT(LUSOLrec *LUSOL, int *INFORM, REAL V[], int NZidx[]) #endif int K, L, L1, L2, LEN, LENL, LENL0, NUML0; REAL SMALL; - register REALXP SUM; - register REAL HOLD; + REALXP SUM; + REAL HOLD; #if (defined LUSOLFastSolve) && !(defined DoTraceL0) REAL *aptr; int *iptr, *jptr; @@ -661,7 +661,7 @@ void LU6U(LUSOLrec *LUSOL, int *INFORM, REAL V[], REAL W[], int NZidx[]) else { int I, J, K, KLAST, L, L1, L2, L3, NRANK, NRANK1; REAL SMALL; - register REALXP T; + REALXP T; #ifdef LUSOLFastSolve REAL *aptr; int *jptr; @@ -736,7 +736,7 @@ void LU6UT(LUSOLrec *LUSOL, int *INFORM, REAL V[], REAL W[], int NZidx[]) int I, J, K, L, L1, L2, NRANK, NRANK1, *ip = LUSOL->ip + 1, *iq = LUSOL->iq + 1; REAL SMALL; - register REAL T; + REAL T; #ifdef LUSOLFastSolve REAL *aptr; int *jptr; diff --git a/lpsolve/lusol6l0.cpp b/lpsolve/lusol6l0.cpp index a3649d2324..1bc908ca1c 100644 --- a/lpsolve/lusol6l0.cpp +++ b/lpsolve/lusol6l0.cpp @@ -121,7 +121,7 @@ void LU6L0T_v(LUSOLrec *LUSOL, LUSOLmat *mat, REAL V[], int NZidx[], int *INFORM #endif int LEN, K, KK, L, L1, NUML0; REAL SMALL; - register REAL VPIV; + REAL VPIV; #if (defined LUSOLFastSolve) && !(defined DoTraceL0) REAL *aptr; int *jptr; diff --git a/lpsolve/lusol6u.cpp b/lpsolve/lusol6u.cpp index 5ada0d7653..1d0a7b910e 100644 --- a/lpsolve/lusol6u.cpp +++ b/lpsolve/lusol6u.cpp @@ -110,7 +110,7 @@ void LU6U0_v(LUSOLrec *LUSOL, LUSOLmat *mat, REAL V[], REAL W[], int NZidx[], in #endif int LEN, I, K, L, L1, NRANK, NRANK1, KLAST; REAL SMALL; - register REAL T; + REAL T; #if (defined xxLUSOLFastSolve) && !(defined DoTraceU0) REAL *aptr; int *jptr; diff --git a/lpsolve/myblas.cpp b/lpsolve/myblas.cpp index 672df68f00..3ddadb6692 100644 --- a/lpsolve/myblas.cpp +++ b/lpsolve/myblas.cpp @@ -166,7 +166,7 @@ void BLAS_CALLMODEL my_daxpy( int *_n, REAL *_da, REAL *dx, int *_incx, REAL *dy #ifndef DOFASTMATH int m, mp1; #endif - register REAL rda; + REAL rda; REAL da = *_da; int n = *_n, incx = *_incx, incy = *_incy; @@ -336,7 +336,7 @@ void BLAS_CALLMODEL my_dscal (int *_n, REAL *_da, REAL *dx, int *_incx) #ifndef DOFASTMATH int m, mp1, ix; #endif - register REAL rda; + REAL rda; REAL da = *_da; int n = *_n, incx = *_incx; @@ -405,7 +405,7 @@ REAL BLAS_CALLMODEL my_ddot(int *_n, REAL *dx, int *_incx, REAL *dy, int *_incy) jack dongarra, linpack, 3/11/78. modified 12/3/93, array[1] declarations changed to array[*] */ - register REAL dtemp; + REAL dtemp; int i, ix, iy; #ifndef DOFASTMATH int m, mp1; @@ -486,7 +486,7 @@ void BLAS_CALLMODEL my_dswap( int *_n, REAL *dx, int *_incx, REAL *dy, int *_inc int m, mp1, ns; REAL dtemp2, dtemp3; #endif - register REAL dtemp1; + REAL dtemp1; int n = *_n, incx = *_incx, incy = *_incy; if (n <= 0) return; @@ -654,7 +654,7 @@ int idamin( int n, REAL *x, int is ) int BLAS_CALLMODEL my_idamax( int *_n, REAL *x, int *_is ) { - register REAL xmax, xtest; + REAL xmax, xtest; int i, imax = 0; #if !defined DOFASTMATH int ii; @@ -693,7 +693,7 @@ int BLAS_CALLMODEL my_idamax( int *_n, REAL *x, int *_is ) int BLAS_CALLMODEL my_idamin( int *_n, REAL *x, int *_is ) { - register REAL xmin, xtest; + REAL xmin, xtest; int i, imin = 0; #if !defined DOFASTMATH int ii; @@ -743,7 +743,7 @@ REAL BLAS_CALLMODEL my_dnormi( int *_n, REAL *x ) dnormi returns the infinity-norm of the vector x. =============================================================== */ int j; - register REAL hold, absval; + REAL hold, absval; int n = *_n; x--; diff --git a/shared/CMakeLists.txt b/shared/CMakeLists.txt index d9ad0051db..fefad24863 100644 --- a/shared/CMakeLists.txt +++ b/shared/CMakeLists.txt @@ -5,7 +5,7 @@ ##################################################################################################################### set(CMAKE_VERBOSE_MAKEFILE ON) -include_directories(. ../splinter) +include_directories(. ../splinter/include $ENV{ORTOOLSDIR}/include/eigen3 $ENV{ORTOOLSDIR}/include ../) set(SHARED_SRC 6par_gamma.h @@ -69,6 +69,8 @@ set(SHARED_SRC lib_power_electronics.h lib_powerblock.cpp lib_powerblock.h + lib_ptes_chp_dispatch.cpp + lib_ptes_chp_dispatch.h lib_pv_incidence_modifier.cpp lib_pv_incidence_modifier.h lib_pv_io_manager.cpp @@ -97,7 +99,7 @@ set(SHARED_SRC lib_util.h lib_utility_rate.cpp lib_utility_rate.h - lib_utility_rate_equations.cpp + lib_utility_rate_equations.cpp lib_utility_rate_equations.h lib_weatherfile.cpp lib_weatherfile.h @@ -143,6 +145,111 @@ set( DEPENDENCIES splinter ) +if (USE_XPRESS) + if (NOT DEFINED XPRESS_ROOT AND DEFINED ENV{XPRESS_ROOT}) + set(XPRESS_ROOT $ENV{XPRESS_ROOT}) + endif() + add_library(XPRESS::XPRESS UNKNOWN IMPORTED) + + if(UNIX) + target_include_directories(XPRESS::XPRESS SYSTEM INTERFACE "${XPRESS_ROOT}/include") + endif() + + if(APPLE) + set_target_properties(XPRESS::XPRESS PROPERTIES + IMPORTED_LOCATION "${XPRESS_ROOT}/lib/libxprs.dylib") + elseif(UNIX) + set_target_properties(XPRESS::XPRESS PROPERTIES + INTERFACE_LINK_DIRECTORIES "${XPRESS_ROOT}/lib" + IMPORTED_LOCATION ${XPRESS_ROOT}/lib/libxprs.so) + elseif(MSVC) + set_target_properties(XPRESS::XPRESS PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${XPRESS_ROOT}\\include" + IMPORTED_LOCATION "${XPRESS_ROOT}\\lib\\xprs.lib") + else() + message(FATAL_ERROR "XPRESS not supported for ${CMAKE_SYSTEM}") + endif() + target_link_libraries(shared XPRESS::XPRESS) +endif() + + +if (UNIX) + find_package(ortools + CONFIG REQUIRED) + target_link_libraries(shared ortools::ortools) +elseif(MSVC) + function(find_ortools_package library) + find_package(${library} + PATHS "$ENV{ORTOOLSDIR}/lib/cmake/${library}" + "$ENV{ORTOOLSDIR}/cmake" + "$ENV{ORTOOLSDIR}/share/${library}/cmake" + $ENV{ORTOOLSDIR} + REQUIRED + ) + endfunction() + + function(set_library_by_config target library has_d_suffix) + string(REPLACE "::" "_" library_name ${library}) + set(lib_release "LIB_${library_name}_RELEASE") + set(lib_debug "LIB_${library_name}_DEBUG") + if (has_d_suffix) + string(REPLACE ".lib" "d.lib" lib_debug ${lib_debug}) + endif() + set(libs "LIB_${tlibrary_name}") + get_target_property(lib_release ${library} LOCATION) + if (NOT "${lib_release}" STREQUAL "lib_release-NOTFOUND") + string(REPLACE release debug lib_debug ${lib_release}) + set(libs + "$<$>:${lib_release}>" + "$<$:${lib_debug}>") + target_link_libraries(${target} ${libs}) + endif() + endfunction() + + # OR-Tools must be version 9.8 + find_ortools_package(absl) + foreach(_absl_target IN ITEMS absl::atomic_hook absl::errno_saver absl::log_severity absl::nullability absl::raw_logging_internal absl::spinlock_wait absl::config absl::dynamic_annotations absl::core_headers absl::malloc_internal absl::base_internal absl::base absl::throw_delegate absl::pretty_function absl::endian absl::scoped_set_env absl::strerror absl::fast_type_id absl::prefetch absl::algorithm absl::algorithm_container absl::cleanup_internal absl::cleanup absl::btree absl::compressed_tuple absl::fixed_array absl::inlined_vector_internal absl::inlined_vector absl::counting_allocator absl::flat_hash_map absl::flat_hash_set absl::node_hash_map absl::node_hash_set absl::container_memory absl::hash_function_defaults absl::hash_policy_traits absl::common_policy_traits absl::hashtablez_sampler absl::hashtable_debug absl::hashtable_debug_hooks absl::node_slot_policy absl::raw_hash_map absl::container_common absl::raw_hash_set absl::layout absl::crc_cpu_detect absl::crc_internal absl::crc32c absl::non_temporal_arm_intrinsics absl::non_temporal_memcpy absl::crc_cord_state absl::stacktrace absl::symbolize absl::examine_stack absl::failure_signal_handler absl::debugging_internal absl::demangle_internal absl::leak_check absl::debugging absl::flags_path_util absl::flags_program_name absl::flags_config absl::flags_marshalling absl::flags_commandlineflag_internal absl::flags_commandlineflag absl::flags_private_handle_accessor absl::flags_reflection absl::flags_internal absl::flags absl::flags_usage_internal absl::flags_usage absl::flags_parse absl::any_invocable absl::bind_front absl::function_ref absl::hash absl::city absl::low_level_hash absl::log_internal_check_impl absl::log_internal_check_op absl::log_internal_conditions absl::log_internal_config absl::log_internal_flags absl::log_internal_format absl::log_internal_globals absl::log_internal_log_impl absl::log_internal_proto absl::log_internal_message absl::log_internal_log_sink_set absl::log_internal_nullguard absl::log_internal_nullstream absl::log_internal_strip absl::log_internal_voidify absl::log_internal_append_truncated absl::absl_check absl::absl_log absl::check absl::die_if_null absl::log_flags absl::log_globals absl::log_initialize absl::log absl::log_entry absl::log_sink absl::log_sink_registry absl::log_streamer absl::log_internal_structured absl::log_structured absl::memory absl::type_traits absl::meta absl::bits absl::int128 absl::numeric absl::numeric_representation absl::sample_recorder absl::exponential_biased absl::periodic_sampler absl::random_random absl::random_bit_gen_ref absl::random_internal_mock_helpers absl::random_distributions absl::random_seed_gen_exception absl::random_seed_sequences absl::random_internal_traits absl::random_internal_distribution_caller absl::random_internal_fast_uniform_bits absl::random_internal_seed_material absl::random_internal_pool_urbg absl::random_internal_salted_seed_seq absl::random_internal_iostream_state_saver absl::random_internal_generate_real absl::random_internal_wide_multiply absl::random_internal_fastmath absl::random_internal_nonsecure_base absl::random_internal_pcg_engine absl::random_internal_randen_engine absl::random_internal_platform absl::random_internal_randen absl::random_internal_randen_slow absl::random_internal_randen_hwaes absl::random_internal_randen_hwaes_impl absl::random_internal_distribution_test_util absl::random_internal_uniform_helper absl::status absl::statusor absl::string_view absl::strings absl::strings_internal absl::str_format absl::str_format_internal absl::cord_internal absl::cordz_update_tracker absl::cordz_functions absl::cordz_statistics absl::cordz_handle absl::cordz_info absl::cordz_sample_token absl::cordz_update_scope absl::cord absl::graphcycles_internal absl::kernel_timeout_internal absl::synchronization absl::time absl::civil_time absl::time_zone absl::any absl::bad_any_cast absl::bad_any_cast_impl absl::span absl::optional absl::bad_optional_access absl::bad_variant_access absl::variant absl::compare absl::utility absl::if_constexpr) + set_library_by_config(shared ${_absl_target} FALSE) + endforeach() + + find_ortools_package(utf8_range) + set_library_by_config(shared utf8_range::utf8_validity FALSE) + + if (CMAKE_BUILD_TYPE STREQUAL "Debug" OR "Debug" IN_LIST CMAKE_CONFIGURATION_TYPES) + find_library( ZLIBD + NAMES zlibd.lib + PATHS $ENV{ORTOOLSDBDIR}/lib) + target_link_libraries(shared debug ${ZLIBD}) + endif() + find_ortools_package(zlib) + get_target_property(LIB_ZLIB_RELEASE ZLIB::ZLIB LOCATION) + target_link_libraries(shared optimized ${LIB_ZLIB_RELEASE}) + + find_ortools_package(protobuf) + set_library_by_config(shared protobuf::libprotobuf TRUE) + + if(USE_COINOR) + find_ortools_package(CoinUtils) + find_ortools_package(Osi) + find_ortools_package(Clp) + find_ortools_package(Cgl) + find_ortools_package(Cbc) + foreach(_target IN ITEMS Coin::CoinUtils Coin::Osi Coin::Clp Coin::OsiClp Coin::ClpSolver Coin::Cbc Coin::OsiCbc Coin::CbcSolver Coin::Cgl) + set_library_by_config(shared ${_target} FALSE) + endforeach() + endif() + + find_ortools_package(re2) + find_ortools_package(Eigen3) + find_ortools_package(utf8_range) + find_ortools_package(scip) + find_ortools_package(ortools) + + foreach(_target IN ITEMS re2::re2 Eigen3::Eigen utf8_range::utf8_validity libscip ortools::ortools) + set_library_by_config(shared ${_target} FALSE) + endforeach() +endif() + if (UNIX) set(CMAKE_SHARED_LINKER_FLAGS "-lm") endif () diff --git a/shared/lib_battery_capacity.cpp b/shared/lib_battery_capacity.cpp index 1be184caf7..a56b818343 100644 --- a/shared/lib_battery_capacity.cpp +++ b/shared/lib_battery_capacity.cpp @@ -43,7 +43,7 @@ double tolerance = 0.002; // Used for capacity calcs. Please use powerflow_toler Define Capacity Model */ -bool capacity_state::operator==(const capacity_state &p) { +bool capacity_state::operator==(const capacity_state &p) const { bool equal = (q0 == p.q0); equal &= (qmax_lifetime == p.qmax_lifetime); equal &= (qmax_thermal == p.qmax_thermal); diff --git a/shared/lib_battery_capacity.h b/shared/lib_battery_capacity.h index 41e8d7a588..b7229dd036 100644 --- a/shared/lib_battery_capacity.h +++ b/shared/lib_battery_capacity.h @@ -64,7 +64,7 @@ struct capacity_state { friend std::ostream &operator<<(std::ostream &os, const capacity_state &p); - bool operator==(const capacity_state &p); + bool operator==(const capacity_state &p) const; }; struct capacity_params { diff --git a/shared/lib_mlmodel.cpp b/shared/lib_mlmodel.cpp index 6df193d016..151ae1f8cf 100644 --- a/shared/lib_mlmodel.cpp +++ b/shared/lib_mlmodel.cpp @@ -44,11 +44,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include "lib_mlmodel.h" // #include "mlm_spline.h" -#include "bsplinebuilder.h" -#include "datatable.h" +#include +#include static const double k = 1.38064852e-23; // Boltzmann constant [J/K] static const double q = 1.60217662e-19; // Elemenatry charge [C] @@ -74,7 +75,6 @@ static const int AM_MODE_LEE_PANCHULA = 4; mlmodel_module_t::mlmodel_module_t() { - m_bspline3 = BSpline(1); Width = Length = V_mp_ref = I_mp_ref = V_oc_ref = I_sc_ref = S_ref = T_ref = R_shref = R_sh0 = R_shexp = R_s = alpha_isc = beta_voc_spec = E_g = n_0 = mu_n = D2MuTau = T_c_no_tnoct @@ -131,9 +131,9 @@ void mlmodel_module_t::initializeManual() */ DataTable samples; for (int i = 0; i <= IAM_c_cs_elements - 1; i = i + 1) { - samples.addSample(IAM_c_cs_incAngle[i], IAM_c_cs_iamValue[i]); + samples.add_sample(IAM_c_cs_incAngle[i], IAM_c_cs_iamValue[i]); } - m_bspline3 = BSpline::Builder(samples).degree(3).build(); + m_bspline3 = std::make_unique(bspline_interpolator(samples, 3)); isInitialized = true; } @@ -170,11 +170,11 @@ bool mlmodel_module_t::operator() (pvinput_t &input, double T_C, double opvoltag // f_IAM_gnd = std::min(iamSpline(theta_gnd), 1.0); DenseVector x(1); x(0) = theta_beam; - f_IAM_beam = std::min(m_bspline3.eval(x), 1.0); + f_IAM_beam = std::min((*m_bspline3).eval(x)[0], 1.0); x(0) = theta_diff; - f_IAM_diff = std::min(m_bspline3.eval(x), 1.0); + f_IAM_diff = std::min((*m_bspline3).eval(x)[0], 1.0); x(0) = theta_gnd; - f_IAM_gnd = std::min(m_bspline3.eval(x), 1.0); + f_IAM_gnd = std::min((*m_bspline3).eval(x)[0], 1.0); break; } diff --git a/shared/lib_mlmodel.h b/shared/lib_mlmodel.h index f1e8eb9d1e..f7b6edb574 100644 --- a/shared/lib_mlmodel.h +++ b/shared/lib_mlmodel.h @@ -34,7 +34,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef __mlmodel_h #define __mlmodel_h - +#include #include "lib_pvmodel.h" //#include "mlm_spline.h" #include "bspline.h" @@ -108,8 +108,7 @@ class mlmodel_module_t : public pvmodule_t double I_0ref; double I_Lref; double Vbi; -// tk::spline iamSpline; - BSpline m_bspline3; + std::unique_ptr m_bspline3; }; diff --git a/shared/lib_ondinv.cpp b/shared/lib_ondinv.cpp index 078aaa4a39..ba6ae643b9 100644 --- a/shared/lib_ondinv.cpp +++ b/shared/lib_ondinv.cpp @@ -43,8 +43,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "lib_ondinv.h" -#include "bsplinebuilder.h" -#include "datatable.h" +#include +#include const int TEMP_DERATE_ARRAY_LENGTH = 6; @@ -203,8 +203,7 @@ void ond_inverter::initializeManual() Pdc_threshold = 2; std::vector ondspl_X; std::vector ondspl_Y; - DenseVector xSamples(1); - DataTable samples; + std::vector xSamples(1); // int splineIndex; // bool switchoverDone; @@ -271,14 +270,14 @@ void ond_inverter::initializeManual() } */ // SPLINTER - samples.clear(); + DataTable samples; x_max[j] = ondspl_X.back(); for (size_t k = 0; k < ondspl_X.size() && k < ondspl_Y.size(); k++) { - xSamples(0) = ondspl_X[k]; - samples.addSample(xSamples, ondspl_Y[k]); + xSamples[0] = ondspl_X[k]; + samples.add_sample(xSamples, ondspl_Y[k]); } - m_bspline3[j] = BSpline::Builder(samples).degree(3).build(); + m_bspline3.push_back(std::make_unique(bspline_interpolator(samples, 3))); } ondIsInitialized = true; @@ -310,7 +309,7 @@ double ond_inverter::calcEfficiency(double Pdc, int index_eta) { { // eta = effSpline[splineIndex][index_eta](Pdc); x(0) = Pdc; - eta = (m_bspline3[index_eta]).eval(x); + eta = (*m_bspline3[index_eta]).eval(x)[0]; } else { diff --git a/shared/lib_ondinv.h b/shared/lib_ondinv.h index efae89ce34..60415c71e1 100644 --- a/shared/lib_ondinv.h +++ b/shared/lib_ondinv.h @@ -32,10 +32,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef __lib_ondinv_h #define __lib_ondinv_h +#include #include #include //#include "mlm_spline.h" // spline interpolator for efficiency curves -#include "bspline.h" +#include using namespace std; using namespace SPLINTER; @@ -63,10 +64,10 @@ class ond_inverter double INomDC; // [A] double INomAC; // [A] double IMaxAC; // [A] - double TPNom; // [�C] - double TPMax; // [�C] - double TPLim1; // [�C] - double TPLimAbs; // [�C] + double TPNom; // [�C] + double TPMax; // [�C] + double TPLim1; // [�C] + double TPLimAbs; // [�C] double PLim1; // [kW] double PLimAbs; // [kW] double VNomEff[3]; // [V] @@ -87,7 +88,7 @@ class ond_inverter /* inputs */ double Pdc, /* Input power to inverter (Wdc) */ double Vdc, /* Voltage input to inverter (Vdc) */ - double Tamb, /* Ambient temperature (�C) */ + double Tamb, /* Ambient temperature (�C) */ /* outputs */ double *Pac, /* AC output power (Wac) */ @@ -115,9 +116,7 @@ class ond_inverter bool ondIsInitialized; int noOfEfficiencyCurves; -// tk::spline effSpline[2][3]; -// BSpline m_bspline3[2][3]; - BSpline m_bspline3[3]; + std::vector> m_bspline3; double x_max[3]; double x_lim[3]; double Pdc_threshold; @@ -131,8 +130,6 @@ class ond_inverter double T_array[6]; double PAC_array[6]; - - }; #endif diff --git a/shared/lib_ortools.cpp b/shared/lib_ortools.cpp new file mode 100644 index 0000000000..e9e863664a --- /dev/null +++ b/shared/lib_ortools.cpp @@ -0,0 +1,59 @@ +#include "ortools/linear_solver/linear_solver.h" +#include "lib_ptes_chp_dispatch.h" +#include "lib_ortools.h" + +using namespace operations_research; + + +void example::contraint_from_function(MPVariable* var1, MPVariable* var2, double bound, std::string name_pre) { + std::string name = name_pre + "ct" + std::to_string(2) + "end"; + MPConstraint* const ct = solver->MakeRowConstraint(0.0, bound, name); + ct->SetCoefficient(var1, 1); + ct->SetCoefficient(var2, 1); +} + +void example::BasicExample() { + // Create the linear solver. + //std::unique_ptr solver(MPSolver::CreateSolver("XPRESS")); + //std::unique_ptr solver(MPSolver::CreateSolver("SCIP")); + + if (!solver) { + LOG(WARNING) << "Solver unavailable."; + return; + } + + // Creating an array of variables x (another way) + std::vector x, y; + solver->MakeNumVarArray(2, 0.0, 2.0, "x", &x); + //solver->MakeIntVarArray(2, 0.0, 1.0, "y", &y); // binary variable + solver->MakeBoolVarArray(2, "y", &y); // binary variable + + LOG(INFO) << "Number of variables = " << solver->NumVariables(); + + // Create a linear constraint, 0 <= x + y <= 2. + contraint_from_function(x[0], x[1], data, "continous"); + contraint_from_function(y[0], y[1], 1., "binary"); + + LOG(INFO) << "Number of constraints = " << solver->NumConstraints(); + + // Create the objective function + MPObjective* const objective = solver->MutableObjective(); + for (int i = 0; i < 2; ++i) { + objective->SetCoefficient(x[i], obj_coeff[i]); + objective->SetCoefficient(y[i], obj_coeff[i]/4.0); + } + objective->SetMaximization(); + + solver->Solve(); + + LOG(INFO) << "Solution:" << std::endl; + LOG(INFO) << "Objective value = " << objective->Value(); + for (int i = 0; i < 2; ++i) { + LOG(INFO) << "x[" << i << "] = " << x[i]->solution_value(); + } + for (int i = 0; i < 2; ++i) { + LOG(INFO) << "y[" << i << "] = " << y[i]->solution_value(); + } + LOG(INFO) << "Constraint name = " << solver->constraint(0)->name(); + LOG(INFO) << "Constraint name = " << solver->constraint(1)->name(); +} diff --git a/shared/lib_ortools.h b/shared/lib_ortools.h new file mode 100644 index 0000000000..2ded7990ac --- /dev/null +++ b/shared/lib_ortools.h @@ -0,0 +1,20 @@ +#pragma once +#include "ortools/linear_solver/linear_solver.h" + +using namespace operations_research; + +class example { + std::unique_ptr solver; + +public: + example() { + solver = std::unique_ptr(MPSolver::CreateSolver("XPRESS")); + } + + double data; + std::vector obj_coeff; + + void contraint_from_function(MPVariable* var1, MPVariable* var2, double bound, std::string name_pre); + + void BasicExample(); +}; diff --git a/shared/lib_ptes_chp_dispatch.cpp b/shared/lib_ptes_chp_dispatch.cpp new file mode 100644 index 0000000000..848aec9f6c --- /dev/null +++ b/shared/lib_ptes_chp_dispatch.cpp @@ -0,0 +1,939 @@ +#include +#include +#include +#include +#include // for table output + +#include "ortools/base/timer.h" +#include "lib_ptes_chp_dispatch.h" +using namespace operations_research; + +void PTES_CHP_Dispatch_Data::setPrices(std::string sell_price_file, double average_price_multipler /*$/MWhe*/, + double heat_price /*$/MWht*/) { + set_data_by_file(sell_price, sell_price_file); + for (int t = 0; t < sell_price.size(); t++) { + sell_price[t] *= average_price_multipler; + } + purchase_price = sell_price; // sell and purchase price equal + heat_sell_price.resize(n_periods, heat_price); // Set to a constant of $20/MWht +}; + +void PTES_CHP_Dispatch_Data::setHeatLoad(std::string heat_load_file, double multipler /*-*/) { + set_data_by_file(heat_demand, heat_load_file); + for (int t = 0; t < heat_demand.size(); t++) { + heat_demand[t] *= multipler; + } +} + +void PTES_CHP_Dispatch_Data::set_data_by_file(std::vector& data, std::string filepath) { + + std::vector< std::string> data_str; + std::ifstream datafile(filepath); + + char line[250]; + if (datafile.is_open()) { + while (datafile) { + datafile.getline(line, 250); + data_str.push_back(line); + } + } + + data.resize(data_str.size() - 1, 0.); + for (int i = 0; i < data_str.size() - 1; i++) { + data.at(i) = std::stod(data_str.at(i)); + } +} + +void PTES_CHP_Dispatch_Data::setDefaultAssumptions(PtesDesign design) { + eta_amb.resize(n_periods, 1.); // assuming no ambient temperature impact + + // Cost parameters + cycle_ramping_cost = 0.3; // $/MWt + cycle_start_cost = 20.0 * design.cycle_cap; // $/start + heat_pump_ramp_cost = 0.6; // $/MWe + heat_pump_start_cost = 5.0 * design.hp_cap; // $/start + + // Power cycle parameters + double cycle_des_heat = design.cycle_cap / design.cycle_eta; + e_pb_startup = cycle_des_heat * 0.25; // 15-minutes at design + q_pb_max = cycle_des_heat; // Cycle heat input (max) + q_pb_min = cycle_des_heat * 0.3; // 30% turn down + q_pb_startup = cycle_des_heat * 0.25; + w_pb_max = design.cycle_cap; + eta_p = (w_pb_max - w_pb_max * 0.15) / (q_pb_max - q_pb_min); // Assuming 15% power at min turndown + eta_d = 1.0; // this is used to un-normalize the ambient correction -> ignoring at the moment + q_rc = ((cycle_des_heat) - design.cycle_cap) * 0.5320755; // Assume the 60 MWt default value + + // Cycle initial conditions + is_pb_starting0 = false; // Assume cycle is off and not starting up + is_pb_operating0 = false; + q_pb0 = 0.0; + e_pb_start0 = 0.0; + + // minimum up and down time parameters + min_up_down_p.down_time_min = 2.0; + min_up_down_p.up_time_min = 2.0; + min_up_down_p.down_time0 = 10.0; // Enable cycle to start up in period 1 + min_up_down_p.up_time0 = 0.0; + min_up_down_p.time_elapsed.clear(); + for (int t = 0; t < n_periods; t++) { + min_up_down_p.time_elapsed.push_back(delta * (t + 1)); + } + + // Heat pump parameters + e_hp_startup = design.hp_cap * 0.25; // MWhe -> 15-minutes at design + w_hp_max = design.hp_cap; // MWe + w_hp_min = design.hp_cap * 0.3; // MWe -> Assuming a 30% turndown + w_hp_startup = design.hp_cap * 0.25; // MWe + q_hp_max = design.hp_cap * design.hp_cop; + kappa_p = (q_hp_max - q_hp_max * 0.15) / (w_hp_max - w_hp_min); // Assuming 15% heat at min turndown + q_rh = 0.0; // Assuming zero heat rejected during charging + + // Heat pump initial conditions + is_hp_starting0 = false; // Assume heat is off and not starting up + is_hp_operating0 = false; + w_hp0 = 0.0; + e_hp_start0 = 0.0; + + // TES parameters + e_tes_max = design.tes_cap; + e_tes0 = design.tes_cap * 0.05; // Assuming 5% full + e_loss = design.tes_cap * 0.0004; // Determined from SAM's default PTES case + + // Heat offtaker TES parameters + e_ot_max = design.tes_cap * 0.1; // Assuming off-taker storage is 10% + e_ot0 = e_ot_max * 0.05; + e_ot_loss = e_ot_max * 0.0004; // Determined from SAM's default PTES case + q_tes_max = 60.; // TODO: May need to update +} + +ptes_chp_dispatch::ptes_chp_dispatch() { + + initializeSolver(); +} + +void ptes_chp_dispatch::initializeSolver() { + solver = CreateSolver("SCIP"); + //solver = CreateSolver("SCIP"); + //solver = std::unique_ptr(MPSolver::CreateSolver("SCIP")); + if (!solver) { + LOG(WARNING) << "Solver unavailable."; + return; + } + //LOG(INFO) << solver->SolverVersion(); + //solver->SetNumThreads(4); + solver->EnableOutput(); + solver->set_time_limit(180*60*1000); //micro-seconds 120*60 + + //solver_params.SetIntegerParam(MPSolverParameters::PRESOLVE, MPSolverParameters::PresolveValues::PRESOLVE_OFF); + + solver_params.SetDoubleParam(MPSolverParameters::DoubleParam::RELATIVE_MIP_GAP, 1.e-2); // 1.e-2 + + //solver_params.SetDoubleParam(MPSolverParameters::DoubleParam::DUAL_TOLERANCE, 1.e-3); + //solver_params.SetDoubleParam(MPSolverParameters::DoubleParam::PRIMAL_TOLERANCE, 1.e-3); +} + +std::unique_ptr ptes_chp_dispatch::CreateSolver(const std::string& solver_id) { + return std::unique_ptr(MPSolver::CreateSolver(solver_id)); +} + +void ptes_chp_dispatch::createVariables() { + // Continous variables + solver->MakeNumVarArray(params.n_periods, 0.0, params.q_pb_max, "q_c", &vars.q_c); + solver->MakeNumVarArray(params.n_periods, 0.0, params.q_pb_max, "q_delta_c", &vars.q_delta_c); + solver->MakeNumVarArray(params.n_periods, 0.0, params.q_hp_max, "q_h", &vars.q_h); + solver->MakeNumVarArray(params.n_periods, 0.0, std::max(params.q_rc, params.q_rh), "q_r", &vars.q_r); + solver->MakeNumVarArray(params.n_periods, 0.0, params.q_tes_max, "q_tes", &vars.q_tes); + solver->MakeNumVarArray(params.n_periods, 0.0, MPSolver::infinity(), "q_s", &vars.q_s); + solver->MakeNumVarArray(params.n_periods, 0.0, params.e_tes_max, "s", &vars.s); + solver->MakeNumVarArray(params.n_periods, 0.0, config.is_offtaker_tes ? params.e_ot_max : 0.0, "s_ot", &vars.s_ot); + solver->MakeNumVarArray(params.n_periods, 0.0, MPSolver::infinity(), "u_csu", &vars.u_csu); + solver->MakeNumVarArray(params.n_periods, 0.0, MPSolver::infinity(), "u_hsu", &vars.u_hsu); + solver->MakeNumVarArray(params.n_periods, 0.0, params.w_pb_max * 1.2, "w_c", &vars.w_c); + solver->MakeNumVarArray(params.n_periods, 0.0, params.w_hp_max, "w_delta_h", &vars.w_delta_h); + solver->MakeNumVarArray(params.n_periods, 0.0, params.w_hp_max, "w_h", &vars.w_h); + // Binary variables + solver->MakeBoolVarArray(params.n_periods, "y_c", &bin_vars.y_c); + solver->MakeBoolVarArray(params.n_periods, "y_cgb", &bin_vars.y_cgb); + solver->MakeBoolVarArray(params.n_periods, "y_cge", &bin_vars.y_cge); + solver->MakeBoolVarArray(params.n_periods, "y_csu", &bin_vars.y_csu); + solver->MakeBoolVarArray(params.n_periods, "y_csup", &bin_vars.y_csup); + solver->MakeBoolVarArray(params.n_periods, "y_h", &bin_vars.y_h); + solver->MakeBoolVarArray(params.n_periods, "y_hsu", &bin_vars.y_hsu); + solver->MakeBoolVarArray(params.n_periods, "y_hsup", &bin_vars.y_hsup); + + LOG(INFO) << "Number of variables = " << solver->NumVariables(); +} + +void ptes_chp_dispatch::createConstraints() { + /*==== Charging - Heat Pump ====*/ + // Heat pump startup inventory + // u_hsu[t] <= u_hsu[t-1] + Delta * W^hsu * y_hsu[t] + create_startup_inventory_constraint(vars.u_hsu, bin_vars.y_hsu, params.delta * params.w_hp_startup, params.e_hp_start0, "hp_start_inv"); + // Heat pump inventory nonzero + // uhsu[t] <= Eh * yhsu[t] + create_inventory_nonzero_constraint(vars.u_hsu, bin_vars.y_hsu, params.e_hp_startup * 1.00001, "hp_inv_nonzero"); + // Heat pump operation allowed when: + // yh[t] <= uhsu[t] / Eh + yh[t-1] + create_operation_allowed_constraint(bin_vars.y_h, vars.u_hsu, params.e_hp_startup, params.is_hp_operating0, "hp_op_allowed"); + // Heat pump startup can't be enabled after a time step where it was operating + // yhsu[t] + yh[t-1] <= 1 + create_startup_wait_constraint(bin_vars.y_hsu, bin_vars.y_h, params.is_hp_operating0, "hp_su_wait"); + // Heat pump minimum power input requirement + // wh[t] >= Wh{min} * yh[t] + create_minimum_operation_constraint(vars.w_h, bin_vars.y_h, params.w_hp_min, "hp_min_input_power"); + // Limits the electrical power to the heat pump during periods of startup + // wh[t] + Whsu * yhsu[t] <= Wh{max} * yh[t] + create_maximum_operation_wstartup_constraint(vars.w_h, bin_vars.y_hsu, bin_vars.y_h, params.w_hp_startup, params.w_hp_max, "hp_max_input_power"); + // Heat production linearization (heat output as function of power input) + // qh[t] = Kp * wh[t] + ( Qh{max} - Kp * Wh{max}) * yh[t] + double intercept = params.q_hp_max - params.kappa_p * params.w_hp_max; + create_linear_production_constraint(vars.q_h, vars.w_h, bin_vars.y_h, params.kappa_p, intercept, params.eta_amb, "hp_heat_production"); + // Heat pump ramping (positive change) + // wdeltah[t] >= wh[t] - wh[t-1] + create_positive_ramping_constraint(vars.w_delta_h, vars.w_h, params.w_hp0, "hp_ramping"); + // Heat pump startup penalty + // yhsup[t] >= yhsu[t] - yhsu[t-1] + create_startup_penalty_constraint(bin_vars.y_hsup, bin_vars.y_hsu, params.is_hp_starting0, "hp_startup_penalty"); + + /*==== Discharging - Closed Brayton Cycle ====*/ + // Cycle startup inventory + // ucsu[t] <= ucsu[t-1] + Delta * Q^csu * ycsu[t] + create_startup_inventory_constraint(vars.u_csu, bin_vars.y_csu, params.delta * params.q_pb_startup, params.e_pb_start0, "pc_start_inv"); + // Cycle inventory nonzero + // ucsu[t] <= Ec * ycsu[t] + create_inventory_nonzero_constraint(vars.u_csu, bin_vars.y_csu, params.e_pb_startup * 1.00001, "pc_inv_nonzero"); + // Cycle operation allowed when: + // yc[t] <= ucsu[t] / Ec + yc[t-1] + create_operation_allowed_constraint(bin_vars.y_c, vars.u_csu, params.e_pb_startup, params.is_pb_operating0, "pc_op_allowed"); + // Cycle startup can't be enabled after a time step where it was operating + // ycsu[t] + yc[t-1] <= 1 + create_startup_wait_constraint(bin_vars.y_csu, bin_vars.y_c, params.is_pb_operating0, "pc_su_wait"); + // Cycle minimum heat input requirement + // qc[t] >= Qc{min} * yc[t] + create_minimum_operation_constraint(vars.q_c, bin_vars.y_c, params.q_pb_min, "pc_min_input_heat"); + // Limits the thermal power to the cycle during periods of startup + // qc[t] + Qcsu * ycsu[t] <= Qc{max} * yc[t] + create_maximum_operation_wstartup_constraint(vars.q_c, bin_vars.y_csu, bin_vars.y_c, params.q_pb_startup, params.q_pb_max, "pc_max_input_heat"); + // Power production linearization (power output as function of heat input) + // wc[t] = eta^amb[t] * (etap * qc[t] + ( Wc{max} - etap * Qc{max}) * yc[t]) + intercept = params.w_pb_max - params.eta_p * params.q_pb_max; + create_linear_production_constraint(vars.w_c, vars.q_c, bin_vars.y_c, params.eta_p, intercept, params.eta_amb, "hp_heat_production"); + // Cycle ramping (positive change) + // qdeltac[t] >= qc[t] - qc[t-1] + create_positive_ramping_constraint(vars.q_delta_c, vars.q_c, params.q_pb0, "pc_ramping"); + // Cycle startup penalty + // ycsup[t] >= ycsu[t] - ycsu[t-1] + create_startup_penalty_constraint(bin_vars.y_csup, bin_vars.y_csu, params.is_pb_starting0, "pc_startup_penalty"); + // Charging and discharging cannot coincide + // yh[t] + yc[t] <= 1 + create_set_packing_constraint(bin_vars.y_h, bin_vars.y_c, "char_dischar_pack"); + // Minimum up- and down- constraints + // ycgb[t] - ycge[t] = y_c[t] - y_c[t-1] + // sum{tp in Tau : 0 <= deltaE[t] - deltaE[tp] < Yu} ycgb[tp] <= y[t] forall t in Tau : deltaE[t] > (Yu-Yu0)*y0 + // sum{tp in Tau : 0 <= deltaE[t] - deltaE[tp] < Yd} ycge[tp] <= 1 - y[t] forall t in Tau : deltaE[t] > (Yd-Yd0)*(1-y0) + // y_c[t] = y0 forall t in Tau : deltaE[t] <= max{ (Yu - Yu0) * y0 , (Yd - Yd0) * (1 - y0) } + create_min_up_down_constraints(bin_vars.y_c, bin_vars.y_cgb, bin_vars.y_cge, params.is_pb_operating0, params.min_up_down_p, ""); + + /*==== Thermal Energy Storage ====*/ + // Storage energy balance + // s[t] - s[t-1] = Delta * ( qh[t] - qc[t] - Qcsu * ycsu[t]) - Qloss + // if heat demand can be met with PTES hot TES + // s[t] - s[t-1] = Delta * ( qh[t] - qc[t] - Qcsu * ycsu[t] - q_tes[t]) - E_loss + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + MPConstraint* constraint; + std::string name = "tes_balance[" + std::to_string(t) + "]"; + if (t == 0) { + constraint = solver->MakeRowConstraint(params.e_tes0 - params.e_loss, params.e_tes0 - params.e_loss, name); + } + else { + constraint = solver->MakeRowConstraint(-params.e_loss, -params.e_loss, name); + constraint->SetCoefficient(vars.s[t - 1], -1.0); + } + constraint->SetCoefficient(vars.s[t], 1.0); + constraint->SetCoefficient(vars.q_h[t], -params.delta); + constraint->SetCoefficient(vars.q_c[t], params.delta); + constraint->SetCoefficient(bin_vars.y_csu[t], params.delta * params.q_pb_startup); + if (config.is_heat_from_tes_allowed) constraint->SetCoefficient(vars.q_tes[t], params.delta); + } + + /*==== Heat Off-taker ====*/ + // Rejected heat occurs during charging and/or discharging + // q_r[t] <= Qrh * y_h[t] + Qrc * y_c[t] + // TODO: Partload... + // q_r[t] <= Qrh / Qh{max} * q_h[t] + Qrc / Qc{max} * q_c[t] + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + MPConstraint* constraint; + std::string name = "heat_reject[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 0.0, name); + constraint->SetCoefficient(vars.q_r[t], 1.0); + if (config.is_charge_heat_reject) constraint->SetCoefficient(bin_vars.y_h[t], -params.q_rh); + if (config.is_discharge_heat_reject) constraint->SetCoefficient(bin_vars.y_c[t], -params.q_rc); + //if (is_charge_heat_reject) constraint->SetCoefficient(vars.q_h[t], -params.q_rh / params.q_hp_max); + //if (is_discharge_heat_reject) constraint->SetCoefficient(vars.q_c[t], -params.q_rc / params.q_pb_max); + } + + // Heat off-taker demand must be met + // q_s[t] == Q_d[t] + // *** OR *** + // Sold heat must be less than heat off-taker demand + // q_s[t] <= Q_d[t] + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + MPConstraint* constraint; + std::string name = "heat_demand[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(config.is_heat_demand_required ? params.heat_demand[t] : -MPSolver::infinity(), params.heat_demand[t], name); + constraint->SetCoefficient(vars.q_s[t], 1.0); + } + + if (!config.is_offtaker_tes) { + params.e_ot0 = 0.0; // Must be set to zero when not available + params.e_ot_loss = 0.0; + } + + // Heat off-taker storage energy balance + // s_ot[t] - s_ot[t-1] = Delta * ( q_r[t] - q_s[t]) - Eloss + // if heat demand can be met with PTES hot TES + // s_ot[t] - s_ot[t-1] = Delta * ( q_r[t] + q_tes[t] - q_s[t]) - E_ot_loss + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + MPConstraint* constraint; + std::string name = "off_taker_tes_balance[" + std::to_string(t) + "]"; + if (t == 0) { + constraint = solver->MakeRowConstraint(params.e_ot0 - params.e_ot_loss, params.e_ot0 - params.e_ot_loss, name); + } + else { + constraint = solver->MakeRowConstraint(-params.e_ot_loss, -params.e_ot_loss, name); + constraint->SetCoefficient(vars.s_ot[t - 1], -1.0); + } + constraint->SetCoefficient(vars.s_ot[t], 1.0); + constraint->SetCoefficient(vars.q_r[t], -params.delta); + if (config.is_heat_from_tes_allowed) constraint->SetCoefficient(vars.q_tes[t], -params.delta); + constraint->SetCoefficient(vars.q_s[t], params.delta); + } + + LOG(INFO) << "Number of constraints = " << solver->NumConstraints(); +} + +void ptes_chp_dispatch::createObjectiveFunction() { + /*==== Objective Function ====*/ + objective = solver->MutableObjective(); + double common_coeff; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + common_coeff = params.delta * std::pow(params.time_weighting, t); + objective->SetCoefficient(vars.w_c[t], common_coeff * params.sell_price[t]); + if (config.is_heat_valued) { + objective->SetCoefficient(vars.q_s[t], common_coeff * params.heat_sell_price[t]); + } + common_coeff = -params.delta * params.purchase_price[t] * (1. / std::pow(params.time_weighting, t)); + objective->SetCoefficient(vars.w_h[t], common_coeff); + common_coeff *= params.w_hp_startup; + objective->SetCoefficient(bin_vars.y_hsu[t], common_coeff); + // Cost terms + common_coeff = -(1. / std::pow(params.time_weighting, t)); + objective->SetCoefficient(bin_vars.y_csup[t], common_coeff * params.cycle_start_cost); + objective->SetCoefficient(vars.q_delta_c[t], common_coeff * params.cycle_ramping_cost); + objective->SetCoefficient(bin_vars.y_hsup[t], common_coeff * params.heat_pump_start_cost); + objective->SetCoefficient(vars.w_delta_h[t], common_coeff * params.heat_pump_ramp_cost); + } + objective->SetMaximization(); +} + +double ptes_chp_dispatch::optimize(std::string resultsfilepath) { + // Create variables + createVariables(); // This could be moved to the constructor class + + // Create the constraints + createConstraints(); + + // Create the objective function + createObjectiveFunction(); + + //solver->EnableOutput(); + std::clock_t c_start = std::clock(); + MPSolver::ResultStatus result_status = solver->Solve(solver_params); + absl::Duration wall_time = solver->DurationSinceConstruction(); + std::clock_t c_end = std::clock(); + double time_elapsed_sec = (c_end - c_start) / CLOCKS_PER_SEC; + + // Check that the problem has an optimal solution. + if (result_status != MPSolver::OPTIMAL) { // How to handle infeasibilities + //LOG(FATAL) << "The problem does not have an optimal solution."; + solver->Clear(); + vars.Clear(); + bin_vars.Clear(); + return 0.0; + } + + printVariableValuesToConsole(wall_time); + printResultsFile(resultsfilepath); + + // Must clear solver and variables before next solve + solver->Clear(); + vars.Clear(); + bin_vars.Clear(); + + return time_elapsed_sec; +} + +double ptes_chp_dispatch::rollingHorizonoptimize(int opt_horizon, int roll_horizon, std::string resultsfilepath) { + int original_horizon = params.n_periods; + + // Save full vectors + std::vector f_eta_amb = params.eta_amb; + std::vector f_heat_sell_price = params.heat_sell_price; + std::vector f_purchase_price = params.purchase_price; + std::vector f_sell_price = params.sell_price; + std::vector f_heat_demand = params.heat_demand; + + // for loop to set up model, solve, and save results + double n_solves = (int)std::ceil(params.n_periods / roll_horizon); + + params.min_up_down_p.time_elapsed.clear(); + for (int t = 0; t < opt_horizon; t++) { + params.min_up_down_p.time_elapsed.push_back(params.delta * (t + 1)); + } + + std::clock_t c_start = std::clock(); + for (int s = 0; s < n_solves; ++s) { + int sidx = (int)(s * roll_horizon); // window start + //int eidx = (int)(sidx + opt_horizon); // window end + params.n_periods = opt_horizon; + // update parameter vectors + params.eta_amb.resize(params.n_periods); + params.heat_sell_price.resize(params.n_periods); + params.purchase_price.resize(params.n_periods); + params.sell_price.resize(params.n_periods); + params.heat_demand.resize(params.n_periods); + for (int i = 0; i < params.n_periods; ++i) { + int original_idx = sidx + i; + if (original_idx >= original_horizon) original_idx -= original_horizon; // start back at the begining + params.eta_amb[i] = f_eta_amb[original_idx]; + params.heat_sell_price[i] = f_heat_sell_price[original_idx]; + params.purchase_price[i] = f_purchase_price[original_idx]; + params.sell_price[i] = f_sell_price[original_idx]; + params.heat_demand[i] = f_heat_demand[original_idx]; + } + + // create problem and solve + LOG(INFO) << " Solving Optimization Horizon: " << s << std::endl; + createVariables(); + createConstraints(); + createObjectiveFunction(); + MPSolver::ResultStatus result_status = solver->Solve(solver_params); + updateInitialConditions(roll_horizon - 1); + //change n_periods so result file loop works + params.n_periods = roll_horizon; + if (s == 0) + printResultsFile(resultsfilepath); // create file with header + else + printResultsFile(resultsfilepath, true); // append results + + // Must clear solver and variables before next solve + solver->Clear(); + vars.Clear(); + bin_vars.Clear(); + } + + std::clock_t c_end = std::clock(); + double time_elapsed_sec = (c_end - c_start) / CLOCKS_PER_SEC; + LOG(INFO) << "CPU time used: " << time_elapsed_sec << " sec" << std::endl; + + // Return class back to original state + params.n_periods = original_horizon; + params.eta_amb = f_eta_amb; + params.heat_sell_price = f_heat_sell_price; + params.purchase_price = f_purchase_price; + params.sell_price = f_sell_price; + params.heat_demand = f_heat_demand; + + return time_elapsed_sec; +} + +void ptes_chp_dispatch::updateInitialConditions(int init_t) { + // Cycle + params.is_pb_starting0 = bin_vars.y_csu[init_t]->solution_value() ? true : false; + params.is_pb_operating0 = bin_vars.y_c[init_t]->solution_value() ? true : false; + params.q_pb0 = params.is_pb_operating0 ? vars.q_c[init_t]->solution_value() : 0.0; + params.e_pb_start0 = params.is_pb_starting0 ? vars.u_csu[init_t]->solution_value() : 0.0; + // Up time and down time + params.min_up_down_p.time_elapsed.clear(); + for (int t = 0; t < params.n_periods; t++) { + params.min_up_down_p.time_elapsed.push_back(params.delta * (t + 1)); + } + double init_up_time = 0.0; + double init_down_time = 0.0; + if (params.is_pb_operating0) { // cycle is up + for (int t = init_t; t > 0; t--) { + if (bin_vars.y_c[t]->solution_value()) { + init_up_time += params.delta; + } + else break; + } + } + else { + for (int t = init_t; t > 0; t--) { + if (!bin_vars.y_c[t]->solution_value()) { + init_down_time += params.delta; + } + else break; + } + } + params.min_up_down_p.up_time0 = init_up_time; + params.min_up_down_p.down_time0 = init_down_time; + // Heat pump + params.is_hp_starting0 = bin_vars.y_hsu[init_t]->solution_value() ? true : false; + params.is_hp_operating0 = bin_vars.y_h[init_t]->solution_value() ? true : false; + params.w_hp0 = params.is_hp_operating0 ? vars.w_h[init_t]->solution_value() : 0.0; + params.e_hp_start0 = params.is_hp_starting0 ? vars.u_hsu[init_t]->solution_value() : 0.0; + // Storage + params.e_tes0 = std::max(vars.s[init_t]->solution_value(), 0.0); + // Heat off-taker Storage + params.e_ot0 = std::max(vars.s_ot[init_t]->solution_value(), 0.0); +} + +void ptes_chp_dispatch::printVariableValuesToConsole(absl::Duration wall_time) { + LOG(INFO) << "Solution:" << std::endl; + LOG(INFO) << "Objective value = " << objective->Value() << std::endl; + LOG(INFO) << "Interations = " << solver->iterations() << std::endl; + LOG(INFO) << "Wall Time = " << wall_time << std::endl; + LOG(INFO) << "==================================================================" << std::endl; + LOG(INFO) << " Cycle Variable Values " << std::endl; + LOG(INFO) << "==================================================================" << std::endl; + int col_width = 10; + double tol = 1.e-3; + LOG(INFO) << std::setfill(' ') << std::left << std::setw(6) << "Time" + << std::left << std::setw(col_width) << "price" + << std::left << std::setw(col_width) << "y_csup" + << std::left << std::setw(col_width) << "y_csu" + << std::left << std::setw(col_width) << "u_csu" + << std::left << std::setw(col_width) << "y_c" + << std::left << std::setw(col_width) << "w_c" + << std::left << std::setw(col_width) << "q_c" + << std::left << std::setw(col_width) << "q_delta_c" + << std::left << std::setw(col_width) << "y_cgb" + << std::left << std::setw(col_width) << "y_cge" + << std::endl; + for (int t = 0; t < std::min(params.n_periods, 48); ++t) { + LOG(INFO) << std::setfill(' ') << std::left << std::setw(6) << t + << std::left << std::setw(col_width) << params.sell_price[t] + << std::left << std::setw(col_width) << (bin_vars.y_csup[t]->solution_value() ? 1 : 0) + << std::left << std::setw(col_width) << (bin_vars.y_csu[t]->solution_value() ? 1 : 0) + << std::left << std::setw(col_width) << ((std::abs(vars.u_csu[t]->solution_value()) < tol) ? 0.0 : vars.u_csu[t]->solution_value()) + << std::left << std::setw(col_width) << (bin_vars.y_c[t]->solution_value() ? 1 : 0) + << std::left << std::setw(col_width) << ((std::abs(vars.w_c[t]->solution_value()) < tol) ? 0.0 : vars.w_c[t]->solution_value()) + << std::left << std::setw(col_width) << ((std::abs(vars.q_c[t]->solution_value()) < tol) ? 0.0 : vars.q_c[t]->solution_value()) + << std::left << std::setw(col_width) << ((std::abs(vars.q_delta_c[t]->solution_value()) < tol) ? 0.0 : vars.q_delta_c[t]->solution_value()) + << std::left << std::setw(col_width) << (bin_vars.y_cgb[t]->solution_value() ? 1 : 0) + << std::left << std::setw(col_width) << (bin_vars.y_cge[t]->solution_value() ? 1 : 0) + << std::endl; + } + LOG(INFO) << "==================================================================" << std::endl; + LOG(INFO) << " Heat Pump Variable Values " << std::endl; + LOG(INFO) << "==================================================================" << std::endl; + LOG(INFO) << std::setfill(' ') << std::left << std::setw(6) << "Time" + << std::left << std::setw(col_width) << "s" + << std::left << std::setw(col_width) << "y_hsup" + << std::left << std::setw(col_width) << "y_hsu" + << std::left << std::setw(col_width) << "u_hsu" + << std::left << std::setw(col_width) << "y_h" + << std::left << std::setw(col_width) << "w_h" + << std::left << std::setw(col_width) << "q_h" + << std::left << std::setw(col_width) << "w_delta_h" + << std::endl; + for (int t = 0; t < std::min(params.n_periods, 48); ++t) { + LOG(INFO) << std::setfill(' ') << std::left << std::setw(6) << t + << std::left << std::setw(col_width) << ((std::abs(vars.s[t]->solution_value()) < tol) ? 0.0 : vars.s[t]->solution_value()) + << std::left << std::setw(col_width) << (bin_vars.y_hsup[t]->solution_value() ? 1 : 0) + << std::left << std::setw(col_width) << (bin_vars.y_hsu[t]->solution_value() ? 1 : 0) + << std::left << std::setw(col_width) << ((std::abs(vars.u_hsu[t]->solution_value()) < tol) ? 0.0 : vars.u_hsu[t]->solution_value()) + << std::left << std::setw(col_width) << (bin_vars.y_h[t]->solution_value() ? 1 : 0) + << std::left << std::setw(col_width) << ((std::abs(vars.w_h[t]->solution_value()) < tol) ? 0.0 : vars.w_h[t]->solution_value()) + << std::left << std::setw(col_width) << ((std::abs(vars.q_h[t]->solution_value()) < tol) ? 0.0 : vars.q_h[t]->solution_value()) + << std::left << std::setw(col_width) << ((std::abs(vars.w_delta_h[t]->solution_value()) < tol) ? 0.0 : vars.w_delta_h[t]->solution_value()) + << std::endl; + } + LOG(INFO) << "==================================================================" << std::endl; + LOG(INFO) << " Heat Off-Taker Variable Values " << std::endl; + LOG(INFO) << "==================================================================" << std::endl; + LOG(INFO) << std::setfill(' ') << std::left << std::setw(6) << "Time" + << std::left << std::setw(col_width) << "heat_P" + << std::left << std::setw(col_width) << "ht_dem" + << std::left << std::setw(col_width) << "s_ot" + << std::left << std::setw(col_width) << "q_s" + << std::left << std::setw(col_width) << "q_r" + << std::left << std::setw(col_width) << "q_tes" + << std::endl; + for (int t = 0; t < std::min(params.n_periods, 48); ++t) { + LOG(INFO) << std::setfill(' ') << std::left << std::setw(6) << t + << std::left << std::setw(col_width) << params.heat_sell_price[t] + << std::left << std::setw(col_width) << params.heat_demand[t] + << std::left << std::setw(col_width) << ((std::abs(vars.s_ot[t]->solution_value()) < tol) ? 0.0 : vars.s_ot[t]->solution_value()) + << std::left << std::setw(col_width) << ((std::abs(vars.q_s[t]->solution_value()) < tol) ? 0.0 : vars.q_s[t]->solution_value()) + << std::left << std::setw(col_width) << ((std::abs(vars.q_r[t]->solution_value()) < tol) ? 0.0 : vars.q_r[t]->solution_value()) + << std::left << std::setw(col_width) << ((std::abs(vars.q_tes[t]->solution_value()) < tol) ? 0.0 : vars.q_tes[t]->solution_value()) + << std::endl; + } +} + +void ptes_chp_dispatch::printResultsFile(std::string filepath, bool append) { + std::ofstream outputfile; + if (append) + outputfile.open(filepath, std::ios_base::app); + else { + // Only print header when not appending + outputfile.open(filepath); + std::string var_header = "Time, Objective, Objective_wo_weight, Price, y_csup, y_csu, u_csu, y_c, w_c, q_c, q_delta_c, y_cgb, y_cge, " + "s, y_hsup, y_hsu, u_hsu, y_h, w_h, q_h, w_delta_h, " + "heat_price, heat_demand, s_ot, q_s, q_r, q_tes"; + outputfile << var_header << std::endl; + } + + double tol = 1.e3; + double objective_value; + double common_coeff; + + double obj_wo_weight; // Objective function value without time weighting + double coeff_wo_weight; + for (int t = 0; t < params.n_periods; ++t) { + // Calculate objective value for time t + objective_value = 0.0; + obj_wo_weight = 0.0; + + common_coeff = params.delta * std::pow(params.time_weighting, t); + coeff_wo_weight = params.delta; + objective_value += common_coeff * params.sell_price[t] * vars.w_c[t]->solution_value(); + obj_wo_weight += coeff_wo_weight * params.sell_price[t] * vars.w_c[t]->solution_value(); + + if (config.is_heat_valued) { + objective_value += common_coeff * params.heat_sell_price[t] * vars.q_s[t]->solution_value(); + obj_wo_weight += coeff_wo_weight * params.heat_sell_price[t] * vars.q_s[t]->solution_value(); + } + + common_coeff = -params.delta * params.purchase_price[t] * (1. / std::pow(params.time_weighting, t)); + coeff_wo_weight = -params.delta * params.purchase_price[t]; + objective_value += common_coeff * vars.w_h[t]->solution_value(); + obj_wo_weight += coeff_wo_weight * vars.w_h[t]->solution_value(); + + common_coeff *= params.w_hp_startup; + coeff_wo_weight *= params.w_hp_startup; + objective_value += common_coeff * bin_vars.y_hsu[t]->solution_value(); + obj_wo_weight += coeff_wo_weight * bin_vars.y_hsu[t]->solution_value(); + + // Cost terms + common_coeff = -(1. / std::pow(params.time_weighting, t)); + coeff_wo_weight = -1.; + + objective_value += common_coeff * params.cycle_start_cost * bin_vars.y_csup[t]->solution_value(); + objective_value += common_coeff * params.cycle_ramping_cost * vars.q_delta_c[t]->solution_value(); + objective_value += common_coeff * params.heat_pump_start_cost * bin_vars.y_hsup[t]->solution_value(); + objective_value += common_coeff * params.heat_pump_ramp_cost * vars.w_delta_h[t]->solution_value(); + + obj_wo_weight += coeff_wo_weight * params.cycle_start_cost * bin_vars.y_csup[t]->solution_value(); + obj_wo_weight += coeff_wo_weight * params.cycle_ramping_cost * vars.q_delta_c[t]->solution_value(); + obj_wo_weight += coeff_wo_weight * params.heat_pump_start_cost * bin_vars.y_hsup[t]->solution_value(); + obj_wo_weight += coeff_wo_weight * params.heat_pump_ramp_cost * vars.w_delta_h[t]->solution_value(); + + outputfile << t + << ", " << objective_value + << ", " << obj_wo_weight + << ", " << params.sell_price[t] + << ", " << bin_vars.y_csup[t]->solution_value() + << ", " << bin_vars.y_csu[t]->solution_value() + << ", " << ((std::abs(vars.u_csu[t]->solution_value()) < tol) ? 0.0 : vars.u_csu[t]->solution_value()) + << ", " << bin_vars.y_c[t]->solution_value() + << ", " << ((std::abs(vars.w_c[t]->solution_value()) < tol) ? 0.0 : vars.w_c[t]->solution_value()) + << ", " << ((std::abs(vars.q_c[t]->solution_value()) < tol) ? 0.0 : vars.q_c[t]->solution_value()) + << ", " << ((std::abs(vars.q_delta_c[t]->solution_value()) < tol) ? 0.0 : vars.q_delta_c[t]->solution_value()) + << ", " << bin_vars.y_cgb[t]->solution_value() + << ", " << bin_vars.y_cge[t]->solution_value() + << ", " << ((std::abs(vars.s[t]->solution_value()) < tol) ? 0.0 : vars.s[t]->solution_value()) + << ", " << bin_vars.y_hsup[t]->solution_value() + << ", " << bin_vars.y_hsu[t]->solution_value() + << ", " << ((std::abs(vars.u_hsu[t]->solution_value()) < tol) ? 0.0 : vars.u_hsu[t]->solution_value()) + << ", " << bin_vars.y_h[t]->solution_value() + << ", " << ((std::abs(vars.w_h[t]->solution_value()) < tol) ? 0.0 : vars.w_h[t]->solution_value()) + << ", " << ((std::abs(vars.q_h[t]->solution_value()) < tol) ? 0.0 : vars.q_h[t]->solution_value()) + << ", " << ((std::abs(vars.w_delta_h[t]->solution_value()) < tol) ? 0.0 : vars.w_delta_h[t]->solution_value()) + << ", " << params.heat_sell_price[t] + << ", " << params.heat_demand[t] + << ", " << ((std::abs(vars.s_ot[t]->solution_value()) < tol) ? 0.0 : vars.s_ot[t]->solution_value()) + << ", " << ((std::abs(vars.q_s[t]->solution_value()) < tol) ? 0.0 : vars.q_s[t]->solution_value()) + << ", " << ((std::abs(vars.q_r[t]->solution_value()) < tol) ? 0.0 : vars.q_r[t]->solution_value()) + << ", " << ((std::abs(vars.q_tes[t]->solution_value()) < tol) ? 0.0 : vars.q_tes[t]->solution_value()) + << std::endl; + } + outputfile.close(); +} + +void ptes_chp_dispatch::create_startup_inventory_constraint(std::vector su_inv, std::vector su_binary, + double inv_roc, double init_su_inv, std::string name_pre) { + // Start-up inventory constraint for all time periods (0 to n_periods-1) + // General Form: su_inv[t] <= su_inv[t-1] + inv_roc * su_binary[t] + // if (t==0): su_inv[t] <= init_su_inv + inv_roc * su_binary[t] + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + if (t == 0) { + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), init_su_inv, name); + } + else { + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 0.0, name); + constraint->SetCoefficient(su_inv[t - 1], -1.0); + } + constraint->SetCoefficient(su_inv[t], 1.0); + constraint->SetCoefficient(su_binary[t], -inv_roc); + } +} + +void ptes_chp_dispatch::create_inventory_nonzero_constraint(std::vector su_inv, std::vector su_binary, + double su_inv_req, std::string name_pre) { + // Start-up inventory nonzero constraint for all time periods (0 to n_periods-1) + // General Form: su_inv[t] <= su_inv_req * su_binary[t] + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 0.0, name); + constraint->SetCoefficient(su_inv[t], 1.0); + constraint->SetCoefficient(su_binary[t], -su_inv_req); + } +} + +void ptes_chp_dispatch::create_operation_allowed_constraint(std::vector op_binary, std::vector su_inv, + double su_inv_req, int prev_op_state, std::string name_pre) { + // Operation allowing when start-up inventory is fulfilled or previously operating for all time periods (0 to n_periods-1) + // General Form: op_binary[t] <= su_inv[t] / su_inv_req + op_binary[t-1] + // if (t==0): op_binary[t] <= su_inv[t] / su_inv_req + prev_op_state + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + if (t == 0) { + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), su_inv_req * prev_op_state, name); + } + else { + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 0.0, name); + constraint->SetCoefficient(op_binary[t - 1], -su_inv_req); + } + constraint->SetCoefficient(op_binary[t], su_inv_req); + constraint->SetCoefficient(su_inv[t], -1.0); + } +} + +void ptes_chp_dispatch::create_startup_wait_constraint(std::vector su_binary, std::vector op_binary, + int prev_op_state, std::string name_pre) { + // Startup cannot be enabled after a time period where the device was operating for all time periods (0 to n_periods-1) + // General Form: su_binary[t] + op_binary[t-1] <= 1 + // if (t==0): su_binary[t] + prev_op_state <= 1 + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + if (t == 0) { + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 1.0 - prev_op_state, name); + // NOTE: for some reason range constraints are not working for Xpress... need to check the basic example + } + else { + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 1.0, name); + constraint->SetCoefficient(op_binary[t - 1], 1.0); + } + constraint->SetCoefficient(su_binary[t], 1.0); + } +} + +void ptes_chp_dispatch::create_minimum_operation_constraint(std::vector op_lvl, std::vector op_binary, + double min_limit, std::string name_pre) { + // Enforce minimum operation limit when system is operating for all time periods (0 to n_periods-1) + // General Form: op_lvl[t] >= min_limit * op_binary[t] + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(0.0, MPSolver::infinity(), name); + constraint->SetCoefficient(op_lvl[t], 1.0); + constraint->SetCoefficient(op_binary[t], -min_limit); + } +} + +void ptes_chp_dispatch::create_maximum_operation_wstartup_constraint(std::vector op_lvl, std::vector su_binary, std::vector op_binary, + double su_rate, double max_limit, std::string name_pre) { + // Enforce maximum operation limit when system is operating and if starting up for all time periods (0 to n_periods-1) + // General Form: op_lvl[t] + su_rate * su_binary[t] <= max_limit * op_binary[t] + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 0.0, name); + constraint->SetCoefficient(op_lvl[t], 1.0); + constraint->SetCoefficient(su_binary[t], su_rate); + constraint->SetCoefficient(op_binary[t], -max_limit); + } +} + +// Currently not being used +void ptes_chp_dispatch::create_maximum_operation_constraint(std::vector op_lvl, std::vector op_binary, + double max_limit, std::string name_pre) { + // Enforce maximum operation limit when system is operating for all time periods (0 to n_periods-1) + // General Form: op_lvl[t] <= max_limit * op_binary[t] + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 0.0, name); + constraint->SetCoefficient(op_lvl[t], 1.0); + constraint->SetCoefficient(op_binary[t], -max_limit); + } +} + +void ptes_chp_dispatch::create_linear_production_constraint(std::vector output, std::vector input, std::vector op_binary, + double slope, double intercept, std::vector amb_corr, std::string name_pre) { + // Model output production as a linear relationship of input for all time periods (0 to n_periods-1) + // General Form: output[t] = amb_corr[t] * ( slope * input[t] + intercept * op_binary[t]) + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(0.0, 0.0, name); + constraint->SetCoefficient(output[t], 1.0); + constraint->SetCoefficient(input[t], -amb_corr[t] * slope); + constraint->SetCoefficient(op_binary[t], -amb_corr[t] * intercept); + } +} + +void ptes_chp_dispatch::create_positive_ramping_constraint(std::vector ramping, std::vector op_lvl, + double prev_op_rate, std::string name_pre) { + // Calculates positive ramping for all time periods (0 to n_periods-1) + // General Form: ramping[t] >= op_lvl[t] - op_lvl[t-1] + // if (t==0): ramping[t] >= op_lvl[t] - prev_op_rate + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + if (t == 0) { + constraint = solver->MakeRowConstraint(-prev_op_rate, MPSolver::infinity(), name); + } + else { + constraint = solver->MakeRowConstraint(0.0, MPSolver::infinity(), name); + constraint->SetCoefficient(op_lvl[t - 1], 1.0); + } + constraint->SetCoefficient(ramping[t], 1.0); + constraint->SetCoefficient(op_lvl[t], -1.0); + } +} + +void ptes_chp_dispatch::create_startup_penalty_constraint(std::vector penalty_binary, std::vector su_binary, + double prev_su_state, std::string name_pre) { + // Enforces startup penalty for all time periods (0 to n_periods-1) + // General Form: penalty[t] >= su_binary[t] - su_binary[t-1] + // if (t==0): penalty_binary[t] >= su_binary[t] - prev_su_state + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + if (t == 0) { + constraint = solver->MakeRowConstraint(-prev_su_state, MPSolver::infinity(), name); + } + else { + constraint = solver->MakeRowConstraint(0.0, MPSolver::infinity(), name); + constraint->SetCoefficient(su_binary[t - 1], 1.0); + } + constraint->SetCoefficient(penalty_binary[t], 1.0); + constraint->SetCoefficient(su_binary[t], -1.0); + } +} + +void ptes_chp_dispatch::create_set_packing_constraint(std::vector binary1, std::vector binary2, std::string name_pre) { + // Enforces set packing constraint between two binaries variables for all time periods (0 to n_periods-1) + // General Form: binary1[t] + binary2[t] <= 1 + MPConstraint* constraint; + for (int t = 0; t < params.n_periods; ++t) { // For all time periods + std::string name = name_pre + "[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 1.0, name); + constraint->SetCoefficient(binary1[t], 1.0); + constraint->SetCoefficient(binary2[t], 1.0); + } +} + +void ptes_chp_dispatch::create_min_up_down_logic_constraint(std::vector op_binary, std::vector up_binary, std::vector down_binary, + int prev_op_state, std::string name_pre) { + // Binary logic when switching state for tracking up- and down-time for all time periods (0 to n_periods-1) + // General Form: up_binary[t] - down_binary[t] = op_binary[t] - op_binary[t-1] + // if (t==0): up_binary[t] - down_binary[t] = op_binary[t] - prev_op_state + for (int t = 0; t < params.n_periods; t++) { // For all time periods + MPConstraint* constraint; + std::string name = name_pre + "[" + std::to_string(t) + "]"; + if (t == 0) { + constraint = solver->MakeRowConstraint(-prev_op_state, -prev_op_state, name); + } + else { + constraint = solver->MakeRowConstraint(0.0, 0.0, name); + constraint->SetCoefficient(op_binary[t - 1], 1.0); + } + constraint->SetCoefficient(up_binary[t], 1.0); + constraint->SetCoefficient(down_binary[t], -1.0); + constraint->SetCoefficient(op_binary[t], -1.0); + } +} + +void ptes_chp_dispatch::create_min_up_time_constraint(std::vector op_binary, std::vector up_binary, + int prev_op_state, min_up_down_params up_down_params, std::string name_pre) { + // Minimum up-time constraint + // General Form: sum{tp in Tau : 0 <= time_elapsed[t] - time_elapsed[tp] < min_up_time} up_binary[tp] <= op_binary[t] + // forall t in Tau : time_elapsed[t] > (min_up_time - init_up_time) * prev_op_state + for (int t = 0; t < params.n_periods; t++) { // For all time periods + if (up_down_params.time_elapsed.at(t) > (up_down_params.up_time_min - up_down_params.up_time0) * prev_op_state) { + MPConstraint* constraint; + std::string name = name_pre + "[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 0.0, name); + for (int tp = 0; tp < params.n_periods; tp++) { + double delta_time = up_down_params.time_elapsed.at(t) - up_down_params.time_elapsed.at(tp); + if ((delta_time >= 0) && (delta_time < up_down_params.up_time_min)) { + constraint->SetCoefficient(up_binary[tp], 1.0); + } + } + constraint->SetCoefficient(op_binary[t], -1.0); + } + } +} + +void ptes_chp_dispatch::create_min_down_time_constraint(std::vector op_binary, std::vector down_binary, + int prev_op_state, min_up_down_params up_down_params, std::string name_pre) { + // Minimum down-time constraint + // General Form: sum{tp in Tau : 0 <= time_elapsed[t] - time_elapsed[tp] < min_down_time} down_binary[tp] <= 1 - op_binary[t] + // forall t in Tau : time_elapsed[t] > (min_down_time - init_down_time) * (1 - prev_op_state) + for (int t = 0; t < params.n_periods; t++) { // For all time periods + if (up_down_params.time_elapsed.at(t) > (up_down_params.down_time_min - up_down_params.down_time0) * (1 - prev_op_state)) { + MPConstraint* constraint; + std::string name = name_pre + "[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(-MPSolver::infinity(), 1.0, name); + for (int tp = 0; tp < params.n_periods; tp++) { + double delta_time = up_down_params.time_elapsed.at(t) - up_down_params.time_elapsed.at(tp); + if ((delta_time >= 0) && (delta_time < up_down_params.down_time_min)) { + constraint->SetCoefficient(down_binary[tp], 1.0); + } + } + constraint->SetCoefficient(op_binary[t], 1.0); + } + } +} + +void ptes_chp_dispatch::create_init_up_down_time_constraint(std::vector op_binary, int prev_op_state, + min_up_down_params up_down_params, std::string name_pre) { + // Initial minimum up- and down- time enforcement + // General Form: op_binary[t] = prev_op_state + // forall t in Tau : time_elapsed[t] <= max{ (min_up_time - init_up_time) * prev_op_state, + // (min_down_time - init_down_time) * (1 - prev_op_state)} + for (int t = 0; t < params.n_periods; t++) { + if (up_down_params.time_elapsed.at(t) <= std::max((up_down_params.up_time_min - up_down_params.up_time0) * prev_op_state, + (up_down_params.down_time_min - up_down_params.down_time0) * (1 - prev_op_state))) { + MPConstraint* constraint; + std::string name = name_pre + "[" + std::to_string(t) + "]"; + constraint = solver->MakeRowConstraint(prev_op_state, prev_op_state, name); + constraint->SetCoefficient(op_binary[t], 1.0); + } + else break; + } +} + +void ptes_chp_dispatch::create_min_up_down_constraints(std::vector op_binary, std::vector up_binary, std::vector down_binary, + int prev_op_state, min_up_down_params up_down_params, std::string name_pre) { + // Binary logic when switching state + ptes_chp_dispatch::create_min_up_down_logic_constraint(op_binary, up_binary, down_binary, prev_op_state, name_pre + "binary_switch_logic"); + // minimum up-time constraint + ptes_chp_dispatch::create_min_up_time_constraint(op_binary, up_binary, prev_op_state, up_down_params, name_pre + "min_up_time"); + // minimum down-time constraint + ptes_chp_dispatch::create_min_down_time_constraint(op_binary, down_binary, prev_op_state, up_down_params, name_pre + "min_down_time"); + // initial minimum up- and down-time enforcement + ptes_chp_dispatch::create_init_up_down_time_constraint(op_binary, prev_op_state, up_down_params, name_pre + "min_up_ititial"); +} + diff --git a/shared/lib_ptes_chp_dispatch.h b/shared/lib_ptes_chp_dispatch.h new file mode 100644 index 0000000000..0abf20aa26 --- /dev/null +++ b/shared/lib_ptes_chp_dispatch.h @@ -0,0 +1,476 @@ +#pragma once + +#include +#include "ortools/linear_solver/linear_solver.h" +using namespace operations_research; + +struct DispatchConfig { + bool is_offtaker_tes; // Does the heat off-taker have TES? Adds storage constraints for off-taker heat. + bool is_charge_heat_reject; // Does the PTES reject heat during charge? Enables rejected heat constraint during charging operations + bool is_discharge_heat_reject; // Does the PTES reject heat during discharge? Enables rejected heat constraint during discharging operations + bool is_heat_from_tes_allowed; // Can heat off-taker demand be met with PTES hot TES? + bool is_heat_demand_required; // Does the off-taker heat demand have to be met? Adds constraint that the heat demand must be met (can easily cause infeasibility) + bool is_heat_valued; // Is rejected heat valued? Heat to off-taker is valued in the objective function + + DispatchConfig() { + is_offtaker_tes = false; + is_charge_heat_reject = false; + is_discharge_heat_reject = false; + is_heat_from_tes_allowed = false; + is_heat_demand_required = false; + is_heat_valued = false; + }; +}; + +struct PtesDesign { + double cycle_cap; // [MWe] Cycle thermodynamic power + double cycle_eta; // [MWe/MWt] Cycle thermodynamic efficiency + double hp_cop; // [MWt/MWe] Heat Pump Coefficient of Performance + double tes_hrs; // [hours] Hours of storage + double tes_cap; // [MWht] Storage thermal capacity + double hp_cap; // [MWe] Heat pump thermodynamic power + + // initialize PTES design parameters + void init(double cycle_capacity /*MWe*/, double cycle_eff /*MWe/MWt*/, + double heatpump_cop /*MWt/MWe*/, double tes_duration /*hours*/) { + cycle_cap = cycle_capacity; + cycle_eta = cycle_eff; + hp_cop = heatpump_cop; + tes_hrs = tes_duration; + tes_cap = cycle_cap / cycle_eta * tes_hrs; // MWht Storage thermal capacity + hp_cap = (cycle_cap / cycle_eta) / hp_cop; // MWe Heat pump thermodynamic power + }; + +}; + +struct min_up_down_params { + std::vector time_elapsed; // [hr] Cumulative time elapsed at the end of period t + double down_time_min; // [hr] Minimum required power cycle down-time + double up_time_min; // [hr] Minimum required power cycle up-time + double down_time0; // [hr] Time that has passed since the cycle has been down before the initial time step + double up_time0; // [hr] Time that has passed since the cycle has been up before the initial time step + + min_up_down_params() { + down_time_min = std::numeric_limits::quiet_NaN(); + up_time_min = std::numeric_limits::quiet_NaN(); + down_time0 = std::numeric_limits::quiet_NaN(); + up_time0 = std::numeric_limits::quiet_NaN(); + } + + void clear() { + time_elapsed.clear(); + } + + void resize(int nt) { + time_elapsed.resize(nt, 0.); + } +}; + +struct PTES_CHP_Dispatch_Data { + // Parameters + int n_periods; // [-] Number of time steps within the time horizon + double time_weighting; // [-] Weighting factor that discounts future decisions over more imminent ones + double delta; // [hr] Duration of time period + + // Time-indexed Parameters + std::vector eta_amb; // [-] Cycle efficiency ambient temperature adjustment factor in period t + std::vector heat_sell_price; // [$/MWht] Heat sell price in period t + std::vector purchase_price; // [$/MWh] Electricity purchase price in period t + std::vector sell_price; // [$/MWh] Electricity sell price in period t + std::vector heat_demand; // [MWht] Off-taker heat demand in period t + + // Cost Parameters + double cycle_ramping_cost; // [$/MWt-change] Cost to change cycle thermal input level (ramping up) + double cycle_start_cost; // [$/start] Cost to start-up the power cycle + double heat_pump_ramp_cost; // [$/MWe-change] Cost to change heat pump electrical input level (ramping up) + double heat_pump_start_cost; // [$/start] Cost to start-up the heat pump + + // Power block (cycle) parameters + double e_pb_startup; // [MWht] Required energy expended to start the power cycle + double q_pb_max; // [MWt] Maximum operational thermal power input to the power cycle + double q_pb_min; // [MWt] Minimum operational thermal power input to the power cycle + double q_pb_startup; // [MWt] Thermal power input during power cycle start-up + double w_pb_max; // [MWe] Power cycle electric power rated capacity + double eta_p; // [MWe/MWt] Slope of linear approximation of power cycle performance curve + double eta_d; // [MWe/MWt] Cycle nominal efficiency + double q_rc; // [MWt] Thermal power rejected during cycle operations + + // initial conditions - Cycle + bool is_pb_starting0; // [-] Power block is starting at the initial time step + bool is_pb_operating0; // [-] Power block is operating at the initial time step + double q_pb0; // [MWt] Thermal power consumption in the cycle entering the initial time step + double e_pb_start0; // [-] Power block start energy consumed before initial time step + + min_up_down_params min_up_down_p; // Parameters required for minimum up- and down-time contraints + + // Heat pump parameters + double e_hp_startup; // [MWht] Required energy expended to start the heat pump + double w_hp_max; // [MWe] Maximum heat pump electric load + double w_hp_min; // [MWe] Minimum heat pump electric load + double w_hp_startup; // [MWe] Thermal power input during heat pump start-up + double q_hp_max; // [MWt] Heat pump maximimum operational thermal power output + double kappa_p; // [MWt/MWe] Slope of linear approximation of heat pump performance curve + double q_rh; // [MWt] Thermal power rejected during heat pump operations + + // initial conditions - Heat pump + bool is_hp_starting0; // [-] Heat pump is starting at the initial time step + bool is_hp_operating0; // [-] Heat pump is operating at the initial time step + double w_hp0; // [MWe] Electrical power consumption in the heat pump entering the initial time step + double e_hp_start0; // [-] Heat pump start energy consumed before initial time step + + // Thermal energy storage parameters + double e_tes_max; // [MWht] Thermal energy stroage capacity + double e_tes0; // [MWht] Current stored energy capacity + double e_loss; // [MWht] Heat loss from stroage + + // Heat off-taker parameters + double e_ot_max; // [MWht] Heat off-taker thermal energy storage capacity + double e_ot0; // [MWht] Current heat off-taker stored energy capacity + double e_ot_loss; // [MWht] Heat loss from stroage + double q_tes_max; // [MWt] Maximum heat rate that can be pulled from PTES storage + + PTES_CHP_Dispatch_Data() { + n_periods = 8760; + time_weighting = 0.99999; + delta = 1.0; + + cycle_ramping_cost = 0.63; // $/MW cap. form Kumar Gas - Aero Derivative CT (Typical Load Follows) + cycle_start_cost = 24.; // $/MW cap. from Kumar Gas - Aero Derivative CT (Warm Start) + heat_pump_ramp_cost = 0.63; //Assuming the same numbers for heat pump + heat_pump_start_cost = 24.; + + e_pb_startup = std::numeric_limits::quiet_NaN(); + q_pb_max = std::numeric_limits::quiet_NaN(); + q_pb_min = std::numeric_limits::quiet_NaN(); + q_pb_startup = std::numeric_limits::quiet_NaN(); + w_pb_max = std::numeric_limits::quiet_NaN(); + eta_p = std::numeric_limits::quiet_NaN(); + eta_d = std::numeric_limits::quiet_NaN(); + q_rc = std::numeric_limits::quiet_NaN(); + + is_pb_starting0 = false; + is_pb_operating0 = false; + q_pb0 = std::numeric_limits::quiet_NaN(); + e_pb_start0 = std::numeric_limits::quiet_NaN(); + + e_hp_startup = std::numeric_limits::quiet_NaN(); + w_hp_max = std::numeric_limits::quiet_NaN(); + w_hp_min = std::numeric_limits::quiet_NaN(); + w_hp_startup = std::numeric_limits::quiet_NaN(); + q_hp_max = std::numeric_limits::quiet_NaN(); + kappa_p = std::numeric_limits::quiet_NaN(); + q_rh = std::numeric_limits::quiet_NaN(); + + is_hp_starting0 = false; + is_hp_operating0 = false; + w_hp0 = std::numeric_limits::quiet_NaN(); + e_hp_start0 = std::numeric_limits::quiet_NaN(); + + e_tes_max = std::numeric_limits::quiet_NaN(); + e_tes0 = std::numeric_limits::quiet_NaN(); + e_loss = std::numeric_limits::quiet_NaN(); + + e_ot_max = std::numeric_limits::quiet_NaN(); + e_ot0 = std::numeric_limits::quiet_NaN(); + e_ot_loss = std::numeric_limits::quiet_NaN(); + q_tes_max = std::numeric_limits::quiet_NaN(); + } + + // Sets electricity sell and purchase prices as well as heat price + void setPrices(std::string sell_price_file, double average_price /*$/MWhe*/, double heat_price /*$/MWht*/); + + // Sets heat load based on file and multipler + void setHeatLoad(std::string heat_load_file, double multipler = 1.0 /*-*/); + + // Used to set a data vector via a csv file + static void set_data_by_file(std::vector& data, std::string filepath); + + void setDefaultAssumptions(PtesDesign design); + + void clear() + { + min_up_down_p.clear(); + eta_amb.clear(); + heat_sell_price.clear(); + purchase_price.clear(); + sell_price.clear(); + heat_demand.clear(); + } + + void resize(int nt) + { + min_up_down_p.resize(nt); + eta_amb.resize(nt, 0.); + heat_sell_price.resize(nt, 0.); + purchase_price.resize(nt, 0.); + sell_price.resize(nt, 0.); + heat_demand.resize(nt, 0.); + } + +}; + +struct PTES_CHP_Dispatch_Output { + std::vector q_c; // [MWt] Power cycle thermal power utilization in period t + std::vector q_delta_c; // [MWt] Change in power cycle thermal input at time t + std::vector q_h; // [MWt] Heat pump thermal power output in period t + std::vector q_r; // [MWt] Thermal power rejected in period t + std::vector q_s; // [MWt] Thermal power sold to heat off-taker in period t + std::vector s; // [MWht] Expected thermal energy storage charge state + std::vector s_ot; // [MWht] Expected off-taker thermal energy storage charge state + std::vector u_csu; // [MWht] Power cycle start-up energy inventory in period t + std::vector u_hsu; // [MWht] Heat pump start-up energy inventory in period t + std::vector w_c; // [MWe] Power cycle electricity generation in period t + std::vector w_delta_h; // [MWe] Change in heat pump electrical input in period t + std::vector w_h; // [MWe] Power cycle electricity generation in period t + + std::vector y_c; // [-] 1 if cycle is generating electric power in period t; 0 otherwise + std::vector y_cgb; // [-] 1 if cycle begins electric power generation in period t; 0 otherwise + std::vector y_cge; // [-] 1 if cycle stops electric power generation in period t; 0 otherwise + std::vector y_csu; // [-] 1 if cycle is starting up in period t; 0 otherwise + std::vector y_csup; // [-] 1 if cycle start-up cost is incurred in period t; 0 otherwise + std::vector y_h; // [-] 1 if heat pump is operating in period t; 0 otherwise + std::vector y_hsu; // [-] 1 if heat pump is starting up in period t; 0 otherwise + std::vector y_hsup; // [-] 1 if heat pump start-up cost is incurred in period t; 0 otherwise + + void clear() { + q_c.clear(); + q_delta_c.clear(); + q_h.clear(); + q_r.clear(); + q_s.clear(); + s.clear(); + s_ot.clear(); + u_csu.clear(); + u_hsu.clear(); + w_c.clear(); + w_delta_h.clear(); + w_h.clear(); + + y_c.clear(); + y_cgb.clear(); + y_cge.clear(); + y_csu.clear(); + y_csup.clear(); + y_h.clear(); + y_hsu.clear(); + y_hsup.clear(); + } + + void resize(int nt) { + q_c.resize(nt, 0.); + q_delta_c.resize(nt, 0.); + q_h.resize(nt, 0.); + q_r.resize(nt, 0.); + q_s.resize(nt, 0.); + s.resize(nt, 0.); + s_ot.resize(nt, 0.); + u_csu.resize(nt, 0.); + u_hsu.resize(nt, 0.); + w_c.resize(nt, 0.); + w_delta_h.resize(nt, 0.); + w_h.resize(nt, 0.); + + y_c.resize(nt, false); + y_cgb.resize(nt, false); + y_cge.resize(nt, false); + y_csu.resize(nt, false); + y_csup.resize(nt, false); + y_h.resize(nt, false); + y_hsu.resize(nt, false); + y_hsup.resize(nt, false); + } +}; + +class ptes_chp_dispatch +{ + struct ContinuousVariables { + std::vector q_c; // [units] description... + std::vector q_delta_c; + std::vector q_h; + std::vector q_r; + std::vector q_tes; + std::vector q_s; + std::vector s; + std::vector s_ot; + std::vector u_csu; + std::vector u_hsu; + std::vector w_c; + std::vector w_delta_h; + std::vector w_h; + + void Clear() { + q_c.clear(); + q_delta_c.clear(); + q_h.clear(); + q_r.clear(); + q_tes.clear(); + q_s.clear(); + s.clear(); + s_ot.clear(); + u_csu.clear(); + u_hsu.clear(); + w_c.clear(); + w_delta_h.clear(); + w_h.clear(); + } + } vars; + + struct BinaryVariables { + std::vector y_c; + std::vector y_cgb; + std::vector y_cge; + std::vector y_csu; + std::vector y_csup; + std::vector y_h; + std::vector y_hsu; + std::vector y_hsup; + + void Clear() { + y_c.clear(); + y_cgb.clear(); + y_cge.clear(); + y_csu.clear(); + y_csup.clear(); + y_h.clear(); + y_hsu.clear(); + y_hsup.clear(); + } + } bin_vars; + + MPObjective* objective; //const + + // Initialize solver + void initializeSolver(); + + // Create dispatch variables + void createVariables(); + + // Create dispatch constraints + void createConstraints(); + + // Create objective function + void createObjectiveFunction(); + + void printVariableValuesToConsole(absl::Duration wall_time); + + // Print model results to file + void printResultsFile(std::string filepath, bool append = false); + + // Update initial condtions + void updateInitialConditions(int init_t); + + +public: + std::unique_ptr solver; // TODO:: move back to private? + + DispatchConfig config; + + MPSolverParameters solver_params; + + PTES_CHP_Dispatch_Data params; + PTES_CHP_Dispatch_Output outputs; + + PtesDesign design; + + ptes_chp_dispatch(); + + // Create Solver + std::unique_ptr CreateSolver(const std::string& solver_id); + + // Declare dispatch formulation + double optimize(std::string resultsfilepath); + + // Do optimization with rolling horizon + double rollingHorizonoptimize(int opt_horizon, int roll_horizon, std::string resultsfilepath); + + // TODO:These functions should be inherited + + /*Start-up inventory constraint for all time periods(0 to nt - 1) + General Form: su_inv[t] <= su_inv[t-1] + inv_roc * su_binary[t] + if (t==0): su_inv[t] <= init_su_inv + inv_roc * su_binary[t]*/ + void create_startup_inventory_constraint(std::vector su_inv, std::vector su_binary, + double inv_roc, double init_su_inv = 0.0, std::string name_pre = ""); + + /* Start-up inventory nonzero constraint for all time periods(0 to nt - 1) + General Form: su_inv[t] <= su_inv_req * su_binary[t]*/ + void create_inventory_nonzero_constraint(std::vector su_inv, std::vector su_binary, + double su_inv_req, std::string name_pre = ""); + + /*Operation allowing when start - up inventory is fulfilled or previously operating for all time periods(0 to nt - 1) + General Form: op_binary[t] <= su_inv[t] / su_inv_req + op_binary[t-1] + if (t==0): op_binary[t] <= su_inv[t] / su_inv_req + prev_op_state */ + void create_operation_allowed_constraint(std::vector op_binary, std::vector su_inv, + double su_inv_req, int prev_op_state = 0.0, std::string name_pre = ""); + + /* Startup cannot be enabled after a time period where the device was operating for all time periods(0 to nt - 1) + General Form: su_binary[t] + op_binary[t-1] <= 1 + if (t==0): su_binary[t] + prev_op_state <= 1 */ + void create_startup_wait_constraint(std::vector su_binary, std::vector op_binary, + int prev_op_state = 0.0, std::string name_pre = ""); + + /* Enforce minimum operation limit when system is operating for all time periods(0 to nt - 1) + General Form: op_lvl[t] >= min_limit * op_binary[t] */ + void create_minimum_operation_constraint(std::vector op_lvl, std::vector op_binary, + double min_limit, std::string name_pre = ""); + + /* Enforce maximum operation limit when system is operatingand if starting up for all time periods(0 to nt - 1) + General Form: op_lvl[t] + su_rate * su_binary[t] <= max_limit * op_binary[t]*/ + void create_maximum_operation_wstartup_constraint(std::vector op_lvl, std::vector su_binary, std::vector op_binary, + double su_rate, double max_limit, std::string name_pre = ""); + + /* Enforce maximum operation limit when system is operating for all time periods (0 to n_periods-1) + General Form: op_lvl[t] <= max_limit * op_binary[t]*/ + void create_maximum_operation_constraint(std::vector op_lvl, std::vector op_binary, + double max_limit, std::string name_pre = ""); + + /* Model output production as a linear relationship of input for all time periods(0 to nt - 1) + General Form: output[t] = amb_corr[t] * ( slope * input[t] + intercept * op_binary[t])*/ + void create_linear_production_constraint(std::vector output, std::vector input, std::vector op_binary, + double slope, double intercept, std::vector amb_corr, std::string name_pre = ""); + + /* Calculates positive ramping for all time periods(0 to nt - 1) + General Form: ramping[t] >= op_lvl[t] - op_lvl[t-1] + if (t==0): ramping[t] >= op_lvl[t] - prev_op_rate*/ + void create_positive_ramping_constraint(std::vector ramping, std::vector op_lvl, + double prev_op_rate, std::string name_pre = ""); + + /* Enforces startup penalty for all time periods(0 to nt - 1) + General Form: penalty[t] >= su_binary[t] - su_binary[t-1] + if (t==0): penalty_binary[t] >= su_binary[t] - prev_su_state */ + void create_startup_penalty_constraint(std::vector penalty_binary, std::vector su_binary, + double prev_su_state = 0.0, std::string name_pre = ""); + + /*Enforces set packing constraint between two binaries variables for all time periods(0 to nt - 1) + General Form: binary1[t] + binary2[t] <= 1*/ + void create_set_packing_constraint(std::vector binary1, std::vector binary2, std::string name_pre = ""); + + /*Binary logic when switching state for tracking up - and down - time for all time periods(0 to nt - 1) + General Form: up_binary[t] - down_binary[t] = op_binary[t] - op_binary[t-1] + if (t==0): up_binary[t] - down_binary[t] = op_binary[t] - prev_op_state*/ + void create_min_up_down_logic_constraint(std::vector op_binary, std::vector up_binary, std::vector down_binary, + int prev_op_state, std::string name_pre = ""); + + /* Minimum up-time constraint + General Form: sum{tp in Tau : 0 <= time_elapsed[t] - time_elapsed[tp] < min_up_time} up_binary[tp] <= op_binary[t] + forall t in Tau : time_elapsed[t] > (min_up_time - init_up_time) * prev_op_state*/ + void create_min_up_time_constraint(std::vector op_binary, std::vector up_binary, + int prev_op_state, min_up_down_params params, std::string name_pre = ""); + + /* Minimum down-time constraint + General Form: sum{tp in Tau : 0 <= time_elapsed[t] - time_elapsed[tp] < min_down_time} down_binary[tp] <= 1 - op_binary[t] + forall t in Tau : time_elapsed[t] > (min_down_time - init_down_time) * (1 - prev_op_state)*/ + void create_min_down_time_constraint(std::vector op_binary, std::vector down_binary, + int prev_op_state, min_up_down_params params, std::string name_pre = ""); + + /* Initial minimum up- and down-time enforcement + General Form: op_binary[t] = prev_op_state + forall t in Tau : time_elapsed[t] <= max{ (min_up_time - init_up_time) * prev_op_state, + (min_down_time - init_down_time) * (1 - prev_op_state)}*/ + void create_init_up_down_time_constraint(std::vector op_binary, int prev_op_state, min_up_down_params params, std::string name_pre = ""); + + /* Creates minimum up- and down- constraints*/ + void create_min_up_down_constraints(std::vector op_binary, std::vector up_binary, std::vector down_binary, + int prev_op_state, min_up_down_params params, std::string name_pre = ""); + + +}; \ No newline at end of file diff --git a/splinter/CMakeLists.txt b/splinter/CMakeLists.txt index fba7f7e5d0..b6a3271bc6 100644 --- a/splinter/CMakeLists.txt +++ b/splinter/CMakeLists.txt @@ -4,20 +4,22 @@ # ##################################################################################################################### -include_directories(. ../ssc) +include_directories(. include src $ENV{ORTOOLSDIR}/include/eigen3 ../ssc) set(SPLINTER_SRC - bspline.cpp - bsplinebasis.cpp - bsplinebasis1d.cpp - bsplinebuilder.cpp - datapoint.cpp - datatable.cpp - function.cpp - knots.cpp - mykroneckerproduct.cpp - serializer.cpp - utilities.cpp) + src/bspline.cpp + src/bspline_basis.cpp + src/bspline_basis_1d.cpp + src/bspline_builders.cpp + src/bspline_utils.cpp + src/data_point.cpp + src/data_table.cpp + src/function.cpp + src/json_parser.cpp + src/knot_vector.cpp + src/knot_builders.cpp + src/kronecker_product.cpp + src/utilities.cpp) ##################################################################################################################### diff --git a/splinter/Cholesky b/splinter/Cholesky deleted file mode 100644 index f727f5d89c..0000000000 --- a/splinter/Cholesky +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef EIGEN_CHOLESKY_MODULE_H -#define EIGEN_CHOLESKY_MODULE_H - -#include "Core" - -#include "src/Core/util/DisableStupidWarnings.h" - -/** \defgroup Cholesky_Module Cholesky module - * - * - * - * This module provides two variants of the Cholesky decomposition for selfadjoint (hermitian) matrices. - * Those decompositions are accessible via the following MatrixBase methods: - * - MatrixBase::llt(), - * - MatrixBase::ldlt() - * - * \code - * #include - * \endcode - */ - -#include "src/misc/Solve.h" -#include "src/Cholesky/LLT.h" -#include "src/Cholesky/LDLT.h" -#ifdef EIGEN_USE_LAPACKE -#include "src/Cholesky/LLT_MKL.h" -#endif - -#include "src/Core/util/ReenableStupidWarnings.h" - -#endif // EIGEN_CHOLESKY_MODULE_H -/* vim: set filetype=cpp et sw=2 ts=2 ai: */ diff --git a/splinter/Core b/splinter/Core deleted file mode 100644 index 509c529e13..0000000000 --- a/splinter/Core +++ /dev/null @@ -1,376 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2007-2011 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_CORE_H -#define EIGEN_CORE_H - -// first thing Eigen does: stop the compiler from committing suicide -#include "src/Core/util/DisableStupidWarnings.h" - -// then include this file where all our macros are defined. It's really important to do it first because -// it's where we do all the alignment settings (platform detection and honoring the user's will if he -// defined e.g. EIGEN_DONT_ALIGN) so it needs to be done before we do anything with vectorization. -#include "src/Core/util/Macros.h" - -// Disable the ipa-cp-clone optimization flag with MinGW 6.x or newer (enabled by default with -O3) -// See http://eigen.tuxfamily.org/bz/show_bug.cgi?id=556 for details. -#if defined(__MINGW32__) && EIGEN_GNUC_AT_LEAST(4,6) - #pragma GCC optimize ("-fno-ipa-cp-clone") -#endif - -#include - -// this include file manages BLAS and MKL related macros -// and inclusion of their respective header files -#include "src/Core/util/MKL_support.h" - -// if alignment is disabled, then disable vectorization. Note: EIGEN_ALIGN is the proper check, it takes into -// account both the user's will (EIGEN_DONT_ALIGN) and our own platform checks -#if !EIGEN_ALIGN - #ifndef EIGEN_DONT_VECTORIZE - #define EIGEN_DONT_VECTORIZE - #endif -#endif - -#ifdef _MSC_VER - #include // for _aligned_malloc -- need it regardless of whether vectorization is enabled - #if (_MSC_VER >= 1500) // 2008 or later - // Remember that usage of defined() in a #define is undefined by the standard. - // a user reported that in 64-bit mode, MSVC doesn't care to define _M_IX86_FP. - #if (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || defined(_M_X64) - #define EIGEN_SSE2_ON_MSVC_2008_OR_LATER - #endif - #endif -#else - // Remember that usage of defined() in a #define is undefined by the standard - #if (defined __SSE2__) && ( (!defined __GNUC__) || (defined __INTEL_COMPILER) || EIGEN_GNUC_AT_LEAST(4,2) ) - #define EIGEN_SSE2_ON_NON_MSVC_BUT_NOT_OLD_GCC - #endif -#endif - -#ifndef EIGEN_DONT_VECTORIZE - - #if defined (EIGEN_SSE2_ON_NON_MSVC_BUT_NOT_OLD_GCC) || defined(EIGEN_SSE2_ON_MSVC_2008_OR_LATER) - - // Defines symbols for compile-time detection of which instructions are - // used. - // EIGEN_VECTORIZE_YY is defined if and only if the instruction set YY is used - #define EIGEN_VECTORIZE - #define EIGEN_VECTORIZE_SSE - #define EIGEN_VECTORIZE_SSE2 - - // Detect sse3/ssse3/sse4: - // gcc and icc defines __SSE3__, ... - // there is no way to know about this on msvc. You can define EIGEN_VECTORIZE_SSE* if you - // want to force the use of those instructions with msvc. - #ifdef __SSE3__ - #define EIGEN_VECTORIZE_SSE3 - #endif - #ifdef __SSSE3__ - #define EIGEN_VECTORIZE_SSSE3 - #endif - #ifdef __SSE4_1__ - #define EIGEN_VECTORIZE_SSE4_1 - #endif - #ifdef __SSE4_2__ - #define EIGEN_VECTORIZE_SSE4_2 - #endif - - // include files - - // This extern "C" works around a MINGW-w64 compilation issue - // https://sourceforge.net/tracker/index.php?func=detail&aid=3018394&group_id=202880&atid=983354 - // In essence, intrin.h is included by windows.h and also declares intrinsics (just as emmintrin.h etc. below do). - // However, intrin.h uses an extern "C" declaration, and g++ thus complains of duplicate declarations - // with conflicting linkage. The linkage for intrinsics doesn't matter, but at that stage the compiler doesn't know; - // so, to avoid compile errors when windows.h is included after Eigen/Core, ensure intrinsics are extern "C" here too. - // notice that since these are C headers, the extern "C" is theoretically needed anyways. - extern "C" { - // In theory we should only include immintrin.h and not the other *mmintrin.h header files directly. - // Doing so triggers some issues with ICC. However old gcc versions seems to not have this file, thus: - #if defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1110 - #include - #else - #include - #include - #ifdef EIGEN_VECTORIZE_SSE3 - #include - #endif - #ifdef EIGEN_VECTORIZE_SSSE3 - #include - #endif - #ifdef EIGEN_VECTORIZE_SSE4_1 - #include - #endif - #ifdef EIGEN_VECTORIZE_SSE4_2 - #include - #endif - #endif - } // end extern "C" - #elif defined __ALTIVEC__ - #define EIGEN_VECTORIZE - #define EIGEN_VECTORIZE_ALTIVEC - #include - // We need to #undef all these ugly tokens defined in - // => use __vector instead of vector - #undef bool - #undef vector - #undef pixel - #elif defined __ARM_NEON - #define EIGEN_VECTORIZE - #define EIGEN_VECTORIZE_NEON - #include - #endif -#endif - -#if (defined _OPENMP) && (!defined EIGEN_DONT_PARALLELIZE) - #define EIGEN_HAS_OPENMP -#endif - -#ifdef EIGEN_HAS_OPENMP -#include -#endif - -// MSVC for windows mobile does not have the errno.h file -#if !(defined(_MSC_VER) && defined(_WIN32_WCE)) && !defined(__ARMCC_VERSION) -#define EIGEN_HAS_ERRNO -#endif - -#ifdef EIGEN_HAS_ERRNO -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include // for CHAR_BIT -// for min/max: -#include - -// for outputting debug info -#ifdef EIGEN_DEBUG_ASSIGN -#include -#endif - -// required for __cpuid, needs to be included after cmath -#if defined(_MSC_VER) && (defined(_M_IX86)||defined(_M_X64)) && (!defined(_WIN32_WCE)) - #include -#endif - -#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) - #define EIGEN_EXCEPTIONS -#endif - -#ifdef EIGEN_EXCEPTIONS - #include -#endif - -/** \brief Namespace containing all symbols from the %Eigen library. */ -namespace Eigen { - -inline static const char *SimdInstructionSetsInUse(void) { -#if defined(EIGEN_VECTORIZE_SSE4_2) - return "SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2"; -#elif defined(EIGEN_VECTORIZE_SSE4_1) - return "SSE, SSE2, SSE3, SSSE3, SSE4.1"; -#elif defined(EIGEN_VECTORIZE_SSSE3) - return "SSE, SSE2, SSE3, SSSE3"; -#elif defined(EIGEN_VECTORIZE_SSE3) - return "SSE, SSE2, SSE3"; -#elif defined(EIGEN_VECTORIZE_SSE2) - return "SSE, SSE2"; -#elif defined(EIGEN_VECTORIZE_ALTIVEC) - return "AltiVec"; -#elif defined(EIGEN_VECTORIZE_NEON) - return "ARM NEON"; -#else - return "None"; -#endif -} - -} // end namespace Eigen - -#define STAGE10_FULL_EIGEN2_API 10 -#define STAGE20_RESOLVE_API_CONFLICTS 20 -#define STAGE30_FULL_EIGEN3_API 30 -#define STAGE40_FULL_EIGEN3_STRICTNESS 40 -#define STAGE99_NO_EIGEN2_SUPPORT 99 - -#if defined EIGEN2_SUPPORT_STAGE40_FULL_EIGEN3_STRICTNESS - #define EIGEN2_SUPPORT - #define EIGEN2_SUPPORT_STAGE STAGE40_FULL_EIGEN3_STRICTNESS -#elif defined EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API - #define EIGEN2_SUPPORT - #define EIGEN2_SUPPORT_STAGE STAGE30_FULL_EIGEN3_API -#elif defined EIGEN2_SUPPORT_STAGE20_RESOLVE_API_CONFLICTS - #define EIGEN2_SUPPORT - #define EIGEN2_SUPPORT_STAGE STAGE20_RESOLVE_API_CONFLICTS -#elif defined EIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API - #define EIGEN2_SUPPORT - #define EIGEN2_SUPPORT_STAGE STAGE10_FULL_EIGEN2_API -#elif defined EIGEN2_SUPPORT - // default to stage 3, that's what it's always meant - #define EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API - #define EIGEN2_SUPPORT_STAGE STAGE30_FULL_EIGEN3_API -#else - #define EIGEN2_SUPPORT_STAGE STAGE99_NO_EIGEN2_SUPPORT -#endif - -#ifdef EIGEN2_SUPPORT -#undef minor -#endif - -// we use size_t frequently and we'll never remember to prepend it with std:: everytime just to -// ensure QNX/QCC support -using std::size_t; -// gcc 4.6.0 wants std:: for ptrdiff_t -using std::ptrdiff_t; - -/** \defgroup Core_Module Core module - * This is the main module of Eigen providing dense matrix and vector support - * (both fixed and dynamic size) with all the features corresponding to a BLAS library - * and much more... - * - * \code - * #include - * \endcode - */ - -#include "src/Core/util/Constants.h" -#include "src/Core/util/ForwardDeclarations.h" -#include "src/Core/util/Meta.h" -#include "src/Core/util/StaticAssert.h" -#include "src/Core/util/XprHelper.h" -#include "src/Core/util/Memory.h" - -#include "src/Core/NumTraits.h" -#include "src/Core/MathFunctions.h" -#include "src/Core/GenericPacketMath.h" - -#if defined EIGEN_VECTORIZE_SSE - #include "src/Core/arch/SSE/PacketMath.h" - #include "src/Core/arch/SSE/MathFunctions.h" - #include "src/Core/arch/SSE/Complex.h" -#elif defined EIGEN_VECTORIZE_ALTIVEC - #include "src/Core/arch/AltiVec/PacketMath.h" - #include "src/Core/arch/AltiVec/Complex.h" -#elif defined EIGEN_VECTORIZE_NEON - #include "src/Core/arch/NEON/PacketMath.h" - #include "src/Core/arch/NEON/Complex.h" -#endif - -#include "src/Core/arch/Default/Settings.h" - -#include "src/Core/Functors.h" -#include "src/Core/DenseCoeffsBase.h" -#include "src/Core/DenseBase.h" -#include "src/Core/MatrixBase.h" -#include "src/Core/EigenBase.h" - -#ifndef EIGEN_PARSED_BY_DOXYGEN // work around Doxygen bug triggered by Assign.h r814874 - // at least confirmed with Doxygen 1.5.5 and 1.5.6 - #include "src/Core/Assign.h" -#endif - -#include "src/Core/util/BlasUtil.h" -#include "src/Core/DenseStorage.h" -#include "src/Core/NestByValue.h" -#include "src/Core/ForceAlignedAccess.h" -#include "src/Core/ReturnByValue.h" -#include "src/Core/NoAlias.h" -#include "src/Core/PlainObjectBase.h" -#include "src/Core/Matrix.h" -#include "src/Core/Array.h" -#include "src/Core/CwiseBinaryOp.h" -#include "src/Core/CwiseUnaryOp.h" -#include "src/Core/CwiseNullaryOp.h" -#include "src/Core/CwiseUnaryView.h" -#include "src/Core/SelfCwiseBinaryOp.h" -#include "src/Core/Dot.h" -#include "src/Core/StableNorm.h" -#include "src/Core/MapBase.h" -#include "src/Core/Stride.h" -#include "src/Core/Map.h" -#include "src/Core/Block.h" -#include "src/Core/VectorBlock.h" -#include "src/Core/Ref.h" -#include "src/Core/Transpose.h" -#include "src/Core/DiagonalMatrix.h" -#include "src/Core/Diagonal.h" -#include "src/Core/DiagonalProduct.h" -#include "src/Core/PermutationMatrix.h" -#include "src/Core/Transpositions.h" -#include "src/Core/Redux.h" -#include "src/Core/Visitor.h" -#include "src/Core/Fuzzy.h" -#include "src/Core/IO.h" -#include "src/Core/Swap.h" -#include "src/Core/CommaInitializer.h" -#include "src/Core/Flagged.h" -#include "src/Core/ProductBase.h" -#include "src/Core/GeneralProduct.h" -#include "src/Core/TriangularMatrix.h" -#include "src/Core/SelfAdjointView.h" -#include "src/Core/products/GeneralBlockPanelKernel.h" -#include "src/Core/products/Parallelizer.h" -#include "src/Core/products/CoeffBasedProduct.h" -#include "src/Core/products/GeneralMatrixVector.h" -#include "src/Core/products/GeneralMatrixMatrix.h" -#include "src/Core/SolveTriangular.h" -#include "src/Core/products/GeneralMatrixMatrixTriangular.h" -#include "src/Core/products/SelfadjointMatrixVector.h" -#include "src/Core/products/SelfadjointMatrixMatrix.h" -#include "src/Core/products/SelfadjointProduct.h" -#include "src/Core/products/SelfadjointRank2Update.h" -#include "src/Core/products/TriangularMatrixVector.h" -#include "src/Core/products/TriangularMatrixMatrix.h" -#include "src/Core/products/TriangularSolverMatrix.h" -#include "src/Core/products/TriangularSolverVector.h" -#include "src/Core/BandMatrix.h" -#include "src/Core/CoreIterators.h" - -#include "src/Core/BooleanRedux.h" -#include "src/Core/Select.h" -#include "src/Core/VectorwiseOp.h" -#include "src/Core/Random.h" -#include "src/Core/Replicate.h" -#include "src/Core/Reverse.h" -#include "src/Core/ArrayBase.h" -#include "src/Core/ArrayWrapper.h" - -#ifdef EIGEN_USE_BLAS -#include "src/Core/products/GeneralMatrixMatrix_MKL.h" -#include "src/Core/products/GeneralMatrixVector_MKL.h" -#include "src/Core/products/GeneralMatrixMatrixTriangular_MKL.h" -#include "src/Core/products/SelfadjointMatrixMatrix_MKL.h" -#include "src/Core/products/SelfadjointMatrixVector_MKL.h" -#include "src/Core/products/TriangularMatrixMatrix_MKL.h" -#include "src/Core/products/TriangularMatrixVector_MKL.h" -#include "src/Core/products/TriangularSolverMatrix_MKL.h" -#endif // EIGEN_USE_BLAS - -#ifdef EIGEN_USE_MKL_VML -#include "src/Core/Assign_MKL.h" -#endif - -#include "src/Core/GlobalFunctions.h" - -#include "src/Core/util/ReenableStupidWarnings.h" - -#ifdef EIGEN2_SUPPORT -#include "Eigen2Support" -#endif - -#endif // EIGEN_CORE_H diff --git a/splinter/Eigenvalues b/splinter/Eigenvalues deleted file mode 100644 index 53c5a73a27..0000000000 --- a/splinter/Eigenvalues +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef EIGEN_EIGENVALUES_MODULE_H -#define EIGEN_EIGENVALUES_MODULE_H - -#include "Core" - -#include "src/Core/util/DisableStupidWarnings.h" - -#include "Cholesky" -#include "Jacobi" -#include "Householder" -#include "LU" -#include "Geometry" - -/** \defgroup Eigenvalues_Module Eigenvalues module - * - * - * - * This module mainly provides various eigenvalue solvers. - * This module also provides some MatrixBase methods, including: - * - MatrixBase::eigenvalues(), - * - MatrixBase::operatorNorm() - * - * \code - * #include - * \endcode - */ - -#include "src/Eigenvalues/Tridiagonalization.h" -#include "src/Eigenvalues/RealSchur.h" -#include "src/Eigenvalues/EigenSolver.h" -#include "src/Eigenvalues/SelfAdjointEigenSolver.h" -#include "src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h" -#include "src/Eigenvalues/HessenbergDecomposition.h" -#include "src/Eigenvalues/ComplexSchur.h" -#include "src/Eigenvalues/ComplexEigenSolver.h" -#include "src/Eigenvalues/RealQZ.h" -#include "src/Eigenvalues/GeneralizedEigenSolver.h" -#include "src/Eigenvalues/MatrixBaseEigenvalues.h" -#ifdef EIGEN_USE_LAPACKE -#include "src/Eigenvalues/RealSchur_MKL.h" -#include "src/Eigenvalues/ComplexSchur_MKL.h" -#include "src/Eigenvalues/SelfAdjointEigenSolver_MKL.h" -#endif - -#include "src/Core/util/ReenableStupidWarnings.h" - -#endif // EIGEN_EIGENVALUES_MODULE_H -/* vim: set filetype=cpp et sw=2 ts=2 ai: */ diff --git a/splinter/Geometry b/splinter/Geometry deleted file mode 100644 index efd9d4504c..0000000000 --- a/splinter/Geometry +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef EIGEN_GEOMETRY_MODULE_H -#define EIGEN_GEOMETRY_MODULE_H - -#include "Core" - -#include "src/Core/util/DisableStupidWarnings.h" - -#include "SVD" -#include "LU" -#include - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -/** \defgroup Geometry_Module Geometry module - * - * - * - * This module provides support for: - * - fixed-size homogeneous transformations - * - translation, scaling, 2D and 3D rotations - * - quaternions - * - \ref MatrixBase::cross() "cross product" - * - \ref MatrixBase::unitOrthogonal() "orthognal vector generation" - * - some linear components: parametrized-lines and hyperplanes - * - * \code - * #include - * \endcode - */ - -#include "src/Geometry/OrthoMethods.h" -#include "src/Geometry/EulerAngles.h" - -#if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS - #include "src/Geometry/Homogeneous.h" - #include "src/Geometry/RotationBase.h" - #include "src/Geometry/Rotation2D.h" - #include "src/Geometry/Quaternion.h" - #include "src/Geometry/AngleAxis.h" - #include "src/Geometry/Transform.h" - #include "src/Geometry/Translation.h" - #include "src/Geometry/Scaling.h" - #include "src/Geometry/Hyperplane.h" - #include "src/Geometry/ParametrizedLine.h" - #include "src/Geometry/AlignedBox.h" - #include "src/Geometry/Umeyama.h" - - #if defined EIGEN_VECTORIZE_SSE - #include "src/Geometry/arch/Geometry_SSE.h" - #endif -#endif - -#ifdef EIGEN2_SUPPORT -#include "src/Eigen2Support/Geometry/All.h" -#endif - -#include "src/Core/util/ReenableStupidWarnings.h" - -#endif // EIGEN_GEOMETRY_MODULE_H -/* vim: set filetype=cpp et sw=2 ts=2 ai: */ - diff --git a/splinter/Householder b/splinter/Householder deleted file mode 100644 index 6e348db5c4..0000000000 --- a/splinter/Householder +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef EIGEN_HOUSEHOLDER_MODULE_H -#define EIGEN_HOUSEHOLDER_MODULE_H - -#include "Core" - -#include "src/Core/util/DisableStupidWarnings.h" - -/** \defgroup Householder_Module Householder module - * This module provides Householder transformations. - * - * \code - * #include - * \endcode - */ - -#include "src/Householder/Householder.h" -#include "src/Householder/HouseholderSequence.h" -#include "src/Householder/BlockHouseholder.h" - -#include "src/Core/util/ReenableStupidWarnings.h" - -#endif // EIGEN_HOUSEHOLDER_MODULE_H -/* vim: set filetype=cpp et sw=2 ts=2 ai: */ diff --git a/splinter/IterativeLinearSolvers b/splinter/IterativeLinearSolvers deleted file mode 100644 index 0f4159dc19..0000000000 --- a/splinter/IterativeLinearSolvers +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef EIGEN_ITERATIVELINEARSOLVERS_MODULE_H -#define EIGEN_ITERATIVELINEARSOLVERS_MODULE_H - -#include "SparseCore" -#include "OrderingMethods" - -#include "src/Core/util/DisableStupidWarnings.h" - -/** - * \defgroup IterativeLinearSolvers_Module IterativeLinearSolvers module - * - * This module currently provides iterative methods to solve problems of the form \c A \c x = \c b, where \c A is a squared matrix, usually very large and sparse. - * Those solvers are accessible via the following classes: - * - ConjugateGradient for selfadjoint (hermitian) matrices, - * - BiCGSTAB for general square matrices. - * - * These iterative solvers are associated with some preconditioners: - * - IdentityPreconditioner - not really useful - * - DiagonalPreconditioner - also called JAcobi preconditioner, work very well on diagonal dominant matrices. - * - IncompleteILUT - incomplete LU factorization with dual thresholding - * - * Such problems can also be solved using the direct sparse decomposition modules: SparseCholesky, CholmodSupport, UmfPackSupport, SuperLUSupport. - * - * \code - * #include - * \endcode - */ - -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - -#include "src/IterativeLinearSolvers/IterativeSolverBase.h" -#include "src/IterativeLinearSolvers/BasicPreconditioners.h" -#include "src/IterativeLinearSolvers/ConjugateGradient.h" -#include "src/IterativeLinearSolvers/BiCGSTAB.h" -#include "src/IterativeLinearSolvers/IncompleteLUT.h" - -#include "src/Core/util/ReenableStupidWarnings.h" - -#endif // EIGEN_ITERATIVELINEARSOLVERS_MODULE_H diff --git a/splinter/Jacobi b/splinter/Jacobi deleted file mode 100644 index ba8a4dc36a..0000000000 --- a/splinter/Jacobi +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef EIGEN_JACOBI_MODULE_H -#define EIGEN_JACOBI_MODULE_H - -#include "Core" - -#include "src/Core/util/DisableStupidWarnings.h" - -/** \defgroup Jacobi_Module Jacobi module - * This module provides Jacobi and Givens rotations. - * - * \code - * #include - * \endcode - * - * In addition to listed classes, it defines the two following MatrixBase methods to apply a Jacobi or Givens rotation: - * - MatrixBase::applyOnTheLeft() - * - MatrixBase::applyOnTheRight(). - */ - -#include "src/Jacobi/Jacobi.h" - -#include "src/Core/util/ReenableStupidWarnings.h" - -#endif // EIGEN_JACOBI_MODULE_H -/* vim: set filetype=cpp et sw=2 ts=2 ai: */ - diff --git a/splinter/LU b/splinter/LU deleted file mode 100644 index db57955044..0000000000 --- a/splinter/LU +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef EIGEN_LU_MODULE_H -#define EIGEN_LU_MODULE_H - -#include "Core" - -#include "src/Core/util/DisableStupidWarnings.h" - -/** \defgroup LU_Module LU module - * This module includes %LU decomposition and related notions such as matrix inversion and determinant. - * This module defines the following MatrixBase methods: - * - MatrixBase::inverse() - * - MatrixBase::determinant() - * - * \code - * #include - * \endcode - */ - -#include "src/misc/Solve.h" -#include "src/misc/Kernel.h" -#include "src/misc/Image.h" -#include "src/LU/FullPivLU.h" -#include "src/LU/PartialPivLU.h" -#ifdef EIGEN_USE_LAPACKE -#include "src/LU/PartialPivLU_MKL.h" -#endif -#include "src/LU/Determinant.h" -#include "src/LU/Inverse.h" - -#if defined EIGEN_VECTORIZE_SSE - #include "src/LU/arch/Inverse_SSE.h" -#endif - -#ifdef EIGEN2_SUPPORT - #include "src/Eigen2Support/LU.h" -#endif - -#include "src/Core/util/ReenableStupidWarnings.h" - -#endif // EIGEN_LU_MODULE_H -/* vim: set filetype=cpp et sw=2 ts=2 ai: */ diff --git a/splinter/OrderingMethods b/splinter/OrderingMethods deleted file mode 100644 index 7c0f1fffff..0000000000 --- a/splinter/OrderingMethods +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef EIGEN_ORDERINGMETHODS_MODULE_H -#define EIGEN_ORDERINGMETHODS_MODULE_H - -#include "SparseCore" - -#include "src/Core/util/DisableStupidWarnings.h" - -/** - * \defgroup OrderingMethods_Module OrderingMethods module - * - * This module is currently for internal use only - * - * It defines various built-in and external ordering methods for sparse matrices. - * They are typically used to reduce the number of elements during - * the sparse matrix decomposition (LLT, LU, QR). - * Precisely, in a preprocessing step, a permutation matrix P is computed using - * those ordering methods and applied to the columns of the matrix. - * Using for instance the sparse Cholesky decomposition, it is expected that - * the nonzeros elements in LLT(A*P) will be much smaller than that in LLT(A). - * - * - * Usage : - * \code - * #include - * \endcode - * - * A simple usage is as a template parameter in the sparse decomposition classes : - * - * \code - * SparseLU > solver; - * \endcode - * - * \code - * SparseQR > solver; - * \endcode - * - * It is possible as well to call directly a particular ordering method for your own purpose, - * \code - * AMDOrdering ordering; - * PermutationMatrix perm; - * SparseMatrix A; - * //Fill the matrix ... - * - * ordering(A, perm); // Call AMD - * \endcode - * - * \note Some of these methods (like AMD or METIS), need the sparsity pattern - * of the input matrix to be symmetric. When the matrix is structurally unsymmetric, - * Eigen computes internally the pattern of \f$A^T*A\f$ before calling the method. - * If your matrix is already symmetric (at leat in structure), you can avoid that - * by calling the method with a SelfAdjointView type. - * - * \code - * // Call the ordering on the pattern of the lower triangular matrix A - * ordering(A.selfadjointView(), perm); - * \endcode - */ - -#ifndef EIGEN_MPL2_ONLY -#include "src/OrderingMethods/Amd.h" -#endif - -#include "src/OrderingMethods/Ordering.h" -#include "src/Core/util/ReenableStupidWarnings.h" - -#endif // EIGEN_ORDERINGMETHODS_MODULE_H diff --git a/splinter/QR b/splinter/QR deleted file mode 100644 index ac5b026935..0000000000 --- a/splinter/QR +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef EIGEN_QR_MODULE_H -#define EIGEN_QR_MODULE_H - -#include "Core" - -#include "src/Core/util/DisableStupidWarnings.h" - -#include "Cholesky" -#include "Jacobi" -#include "Householder" - -/** \defgroup QR_Module QR module - * - * - * - * This module provides various QR decompositions - * This module also provides some MatrixBase methods, including: - * - MatrixBase::qr(), - * - * \code - * #include - * \endcode - */ - -#include "src/misc/Solve.h" -#include "src/QR/HouseholderQR.h" -#include "src/QR/FullPivHouseholderQR.h" -#include "src/QR/ColPivHouseholderQR.h" -#ifdef EIGEN_USE_LAPACKE -#include "src/QR/HouseholderQR_MKL.h" -#include "src/QR/ColPivHouseholderQR_MKL.h" -#endif - -#ifdef EIGEN2_SUPPORT -#include "src/Eigen2Support/QR.h" -#endif - -#include "src/Core/util/ReenableStupidWarnings.h" - -#ifdef EIGEN2_SUPPORT -#include "Eigenvalues" -#endif - -#endif // EIGEN_QR_MODULE_H -/* vim: set filetype=cpp et sw=2 ts=2 ai: */ diff --git a/splinter/SVD b/splinter/SVD deleted file mode 100644 index fd310017ad..0000000000 --- a/splinter/SVD +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef EIGEN_SVD_MODULE_H -#define EIGEN_SVD_MODULE_H - -#include "QR" -#include "Householder" -#include "Jacobi" - -#include "src/Core/util/DisableStupidWarnings.h" - -/** \defgroup SVD_Module SVD module - * - * - * - * This module provides SVD decomposition for matrices (both real and complex). - * This decomposition is accessible via the following MatrixBase method: - * - MatrixBase::jacobiSvd() - * - * \code - * #include - * \endcode - */ - -#include "src/misc/Solve.h" -#include "src/SVD/JacobiSVD.h" -#if defined(EIGEN_USE_LAPACKE) && !defined(EIGEN_USE_LAPACKE_STRICT) -#include "src/SVD/JacobiSVD_MKL.h" -#endif -#include "src/SVD/UpperBidiagonalization.h" - -#ifdef EIGEN2_SUPPORT -#include "src/Eigen2Support/SVD.h" -#endif - -#include "src/Core/util/ReenableStupidWarnings.h" - -#endif // EIGEN_SVD_MODULE_H -/* vim: set filetype=cpp et sw=2 ts=2 ai: */ diff --git a/splinter/SparseCholesky b/splinter/SparseCholesky deleted file mode 100644 index 9f5056aa1a..0000000000 --- a/splinter/SparseCholesky +++ /dev/null @@ -1,47 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2013 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSECHOLESKY_MODULE_H -#define EIGEN_SPARSECHOLESKY_MODULE_H - -#include "SparseCore" -#include "OrderingMethods" - -#include "src/Core/util/DisableStupidWarnings.h" - -/** - * \defgroup SparseCholesky_Module SparseCholesky module - * - * This module currently provides two variants of the direct sparse Cholesky decomposition for selfadjoint (hermitian) matrices. - * Those decompositions are accessible via the following classes: - * - SimplicialLLt, - * - SimplicialLDLt - * - * Such problems can also be solved using the ConjugateGradient solver from the IterativeLinearSolvers module. - * - * \code - * #include - * \endcode - */ - -#ifdef EIGEN_MPL2_ONLY -#error The SparseCholesky module has nothing to offer in MPL2 only mode -#endif - -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" -#include "src/SparseCholesky/SimplicialCholesky.h" - -#ifndef EIGEN_MPL2_ONLY -#include "src/SparseCholesky/SimplicialCholesky_impl.h" -#endif - -#include "src/Core/util/ReenableStupidWarnings.h" - -#endif // EIGEN_SPARSECHOLESKY_MODULE_H diff --git a/splinter/SparseCore b/splinter/SparseCore deleted file mode 100644 index 24bcf0156b..0000000000 --- a/splinter/SparseCore +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef EIGEN_SPARSECORE_MODULE_H -#define EIGEN_SPARSECORE_MODULE_H - -#include "Core" - -#include "src/Core/util/DisableStupidWarnings.h" - -#include -#include -#include -#include -#include - -/** - * \defgroup SparseCore_Module SparseCore module - * - * This module provides a sparse matrix representation, and basic associated matrix manipulations - * and operations. - * - * See the \ref TutorialSparse "Sparse tutorial" - * - * \code - * #include - * \endcode - * - * This module depends on: Core. - */ - -namespace Eigen { - -/** The type used to identify a general sparse storage. */ -struct Sparse {}; - -} - -#include "src/SparseCore/SparseUtil.h" -#include "src/SparseCore/SparseMatrixBase.h" -#include "src/SparseCore/CompressedStorage.h" -#include "src/SparseCore/AmbiVector.h" -#include "src/SparseCore/SparseMatrix.h" -#include "src/SparseCore/MappedSparseMatrix.h" -#include "src/SparseCore/SparseVector.h" -#include "src/SparseCore/SparseBlock.h" -#include "src/SparseCore/SparseTranspose.h" -#include "src/SparseCore/SparseCwiseUnaryOp.h" -#include "src/SparseCore/SparseCwiseBinaryOp.h" -#include "src/SparseCore/SparseDot.h" -#include "src/SparseCore/SparsePermutation.h" -#include "src/SparseCore/SparseRedux.h" -#include "src/SparseCore/SparseFuzzy.h" -#include "src/SparseCore/ConservativeSparseSparseProduct.h" -#include "src/SparseCore/SparseSparseProductWithPruning.h" -#include "src/SparseCore/SparseProduct.h" -#include "src/SparseCore/SparseDenseProduct.h" -#include "src/SparseCore/SparseDiagonalProduct.h" -#include "src/SparseCore/SparseTriangularView.h" -#include "src/SparseCore/SparseSelfAdjointView.h" -#include "src/SparseCore/TriangularSolver.h" -#include "src/SparseCore/SparseView.h" - -#include "src/Core/util/ReenableStupidWarnings.h" - -#endif // EIGEN_SPARSECORE_MODULE_H - diff --git a/splinter/SparseLU b/splinter/SparseLU deleted file mode 100644 index 8527a49bd8..0000000000 --- a/splinter/SparseLU +++ /dev/null @@ -1,49 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2012 Désiré Nuentsa-Wakam -// Copyright (C) 2012 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SPARSELU_MODULE_H -#define EIGEN_SPARSELU_MODULE_H - -#include "SparseCore" - -/** - * \defgroup SparseLU_Module SparseLU module - * This module defines a supernodal factorization of general sparse matrices. - * The code is fully optimized for supernode-panel updates with specialized kernels. - * Please, see the documentation of the SparseLU class for more details. - */ - -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - -// Ordering interface -#include "OrderingMethods" - -#include "src/SparseLU/SparseLU_gemm_kernel.h" - -#include "src/SparseLU/SparseLU_Structs.h" -#include "src/SparseLU/SparseLU_SupernodalMatrix.h" -#include "src/SparseLU/SparseLUImpl.h" -#include "src/SparseCore/SparseColEtree.h" -#include "src/SparseLU/SparseLU_Memory.h" -#include "src/SparseLU/SparseLU_heap_relax_snode.h" -#include "src/SparseLU/SparseLU_relax_snode.h" -#include "src/SparseLU/SparseLU_pivotL.h" -#include "src/SparseLU/SparseLU_panel_dfs.h" -#include "src/SparseLU/SparseLU_kernel_bmod.h" -#include "src/SparseLU/SparseLU_panel_bmod.h" -#include "src/SparseLU/SparseLU_column_dfs.h" -#include "src/SparseLU/SparseLU_column_bmod.h" -#include "src/SparseLU/SparseLU_copy_to_ucol.h" -#include "src/SparseLU/SparseLU_pruneL.h" -#include "src/SparseLU/SparseLU_Utils.h" -#include "src/SparseLU/SparseLU.h" - -#endif // EIGEN_SPARSELU_MODULE_H diff --git a/splinter/SparseQR b/splinter/SparseQR deleted file mode 100644 index 4ee42065ee..0000000000 --- a/splinter/SparseQR +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef EIGEN_SPARSEQR_MODULE_H -#define EIGEN_SPARSEQR_MODULE_H - -#include "SparseCore" -#include "OrderingMethods" -#include "src/Core/util/DisableStupidWarnings.h" - -/** \defgroup SparseQR_Module SparseQR module - * \brief Provides QR decomposition for sparse matrices - * - * This module provides a simplicial version of the left-looking Sparse QR decomposition. - * The columns of the input matrix should be reordered to limit the fill-in during the - * decomposition. Built-in methods (COLAMD, AMD) or external methods (METIS) can be used to this end. - * See the \link OrderingMethods_Module OrderingMethods\endlink module for the list - * of built-in and external ordering methods. - * - * \code - * #include - * \endcode - * - * - */ - -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - -#include "OrderingMethods" -#include "src/SparseCore/SparseColEtree.h" -#include "src/SparseQR/SparseQR.h" - -#include "src/Core/util/ReenableStupidWarnings.h" - -#endif diff --git a/splinter/bspline.cpp b/splinter/bspline.cpp deleted file mode 100644 index d4d62d2929..0000000000 --- a/splinter/bspline.cpp +++ /dev/null @@ -1,443 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ -#include - -#include "bspline.h" -#include "bsplinebasis.h" -#include "mykroneckerproduct.h" -#include "unsupported/Eigen/KroneckerProduct" -#include "linearsolvers.h" -#include "serializer.h" -#include "utilities.h" - -namespace SPLINTER -{ - -BSpline::BSpline() - : Function(1) -{} - -BSpline::BSpline(unsigned int numVariables) - : Function(numVariables) -{} - -/* - * Constructors for multivariate B-spline using explicit data - */ -BSpline::BSpline(std::vector> knotVectors, std::vector basisDegrees) - : Function(knotVectors.size()), - basis(BSplineBasis(knotVectors, basisDegrees)), - coefficients(DenseVector::Zero(1)), - knotaverages(computeKnotAverages()) -{ - // Initialize coefficients to ones - setCoefficients(DenseVector::Ones(basis.getNumBasisFunctions())); - - checkControlPoints(); -} - -BSpline::BSpline(std::vector coefficients, std::vector> knotVectors, std::vector basisDegrees) - : BSpline(vectorToDenseVector(coefficients), knotVectors, basisDegrees) -{ -} - -BSpline::BSpline(DenseVector coefficients, std::vector> knotVectors, std::vector basisDegrees) - : Function(knotVectors.size()), - basis(BSplineBasis(knotVectors, basisDegrees)), - coefficients(coefficients), - knotaverages(computeKnotAverages()) -{ - setCoefficients(coefficients); - - checkControlPoints(); -} - -/* - * Construct from saved data - */ -BSpline::BSpline(const char *fileName) - : BSpline(std::string(fileName)) -{ -} - -BSpline::BSpline(const std::string &fileName) - : Function(1) -{ - load(fileName); -} - -/** - * Returns the function value at x - */ -double BSpline::eval(DenseVector x) const -{ - checkInput(x); - // NOTE: casting to DenseVector to allow accessing as res(0) - DenseVector res = coefficients.transpose()*evalBasis(x); - return res(0); -} - -/** - * Returns the (1 x numVariables) Jacobian evaluated at x - */ -DenseMatrix BSpline::evalJacobian(DenseVector x) const -{ - checkInput(x); - return coefficients.transpose()*evalBasisJacobian(x); -} - -/* - * Returns the Hessian evaluated at x. - * The Hessian is an n x n matrix, - * where n is the dimension of x. - */ -DenseMatrix BSpline::evalHessian(DenseVector x) const -{ - checkInput(x); - - #ifndef NDEBUG - if (!pointInDomain(x)) - throw Exception("BSpline::evalHessian: Evaluation at point outside domain."); - #endif // NDEBUG - - DenseMatrix H; - H.setZero(1,1); - DenseMatrix identity = DenseMatrix::Identity(numVariables, numVariables); - DenseMatrix caug = kroneckerProduct(identity, coefficients.transpose()); - DenseMatrix DB = basis.evalBasisHessian(x); - H = caug*DB; - - // Fill in upper triangular of Hessian - for (size_t i = 0; i < numVariables; ++i) - for (size_t j = i+1; j < numVariables; ++j) - H(i,j) = H(j,i); - - return H; -} - -// Evaluation of B-spline basis functions -SparseVector BSpline::evalBasis(DenseVector x) const -{ - #ifndef NDEBUG - if (!pointInDomain(x)) - throw Exception("BSpline::evalBasis: Evaluation at point outside domain."); - #endif // NDEBUG - - return basis.eval(x); -} - -SparseMatrix BSpline::evalBasisJacobian(DenseVector x) const -{ - #ifndef NDEBUG - if (!pointInDomain(x)) - throw Exception("BSpline::evalBasisJacobian: Evaluation at point outside domain."); - #endif // NDEBUG - - //SparseMatrix Bi = basis.evalBasisJacobian(x); // Sparse Jacobian implementation - //SparseMatrix Bi = basis.evalBasisJacobian2(x); // Sparse Jacobian implementation - DenseMatrix Bi = basis.evalBasisJacobianOld(x); // Old Jacobian implementation - - return Bi.sparseView(); -} - -std::vector BSpline::getNumBasisFunctionsPerVariable() const -{ - std::vector ret; - for (unsigned int i = 0; i < numVariables; i++) - ret.push_back(basis.getNumBasisFunctions(i)); - return ret; -} - -std::vector< std::vector > BSpline::getKnotVectors() const -{ - return basis.getKnotVectors(); -} - -std::vector BSpline::getBasisDegrees() const -{ - return basis.getBasisDegrees(); -} - -std::vector BSpline::getDomainUpperBound() const -{ - return basis.getSupportUpperBound(); -} - -std::vector BSpline::getDomainLowerBound() const -{ - return basis.getSupportLowerBound(); -} - -DenseMatrix BSpline::getControlPoints() const -{ - int nc = coefficients.size(); - DenseMatrix controlPoints(nc, numVariables + 1); - - controlPoints.block(0, 0, nc, numVariables) = knotaverages; - controlPoints.block(0, numVariables, nc, 1) = coefficients; - - return controlPoints; -} - -void BSpline::setCoefficients(const DenseVector &coefficients) -{ - if (coefficients.size() != getNumBasisFunctions()) - throw Exception("BSpline::setControlPoints: Incompatible size of coefficient vector."); - - this->coefficients = coefficients; - checkControlPoints(); -} - -void BSpline::setControlPoints(const DenseMatrix &controlPoints) -{ - if (controlPoints.cols() != numVariables + 1) - throw Exception("BSpline::setControlPoints: Incompatible size of control point matrix."); - - int nc = controlPoints.rows(); - - knotaverages = controlPoints.block(0, 0, nc, numVariables); - coefficients = controlPoints.block(0, numVariables, nc, 1); - - checkControlPoints(); -} - -void BSpline::updateControlPoints(const DenseMatrix &A) -{ - if (A.cols() != coefficients.rows() || A.cols() != knotaverages.rows()) - throw Exception("BSpline::updateControlPoints: Incompatible size of linear transformation matrix."); - coefficients = A*coefficients; - knotaverages = A*knotaverages; -} - -void BSpline::checkControlPoints() const -{ - if (coefficients.rows() != knotaverages.rows()) - throw Exception("BSpline::checkControlPoints: Inconsistent size of coefficients and knot averages matrices."); - if (knotaverages.cols() != numVariables) - throw Exception("BSpline::checkControlPoints: Inconsistent size of knot averages matrix."); -} - -bool BSpline::pointInDomain(DenseVector x) const -{ - return basis.insideSupport(x); -} - -void BSpline::reduceSupport(std::vector lb, std::vector ub, bool doRegularizeKnotVectors) -{ - if (lb.size() != numVariables || ub.size() != numVariables) - throw Exception("BSpline::reduceSupport: Inconsistent vector sizes!"); - - std::vector sl = basis.getSupportLowerBound(); - std::vector su = basis.getSupportUpperBound(); - - for (unsigned int dim = 0; dim < numVariables; dim++) - { - // Check if new domain is empty - if (ub.at(dim) <= lb.at(dim) || lb.at(dim) >= su.at(dim) || ub.at(dim) <= sl.at(dim)) - throw Exception("BSpline::reduceSupport: Cannot reduce B-spline domain to empty set!"); - - // Check if new domain is a strict subset - if (su.at(dim) < ub.at(dim) || sl.at(dim) > lb.at(dim)) - throw Exception("BSpline::reduceSupport: Cannot expand B-spline domain!"); - - // Tightest possible - sl.at(dim) = lb.at(dim); - su.at(dim) = ub.at(dim); - } - - if (doRegularizeKnotVectors) - { - regularizeKnotVectors(sl, su); - } - - // Remove knots and control points that are unsupported with the new bounds - if (!removeUnsupportedBasisFunctions(sl, su)) - { - throw Exception("BSpline::reduceSupport: Failed to remove unsupported basis functions!"); - } -} - -void BSpline::globalKnotRefinement() -{ - // Compute knot insertion matrix - SparseMatrix A = basis.refineKnots(); - - // Update control points - updateControlPoints(A); -} - -void BSpline::localKnotRefinement(DenseVector x) -{ - // Compute knot insertion matrix - SparseMatrix A = basis.refineKnotsLocally(x); - - // Update control points - updateControlPoints(A); -} - -void BSpline::decomposeToBezierForm() -{ - // Compute knot insertion matrix - SparseMatrix A = basis.decomposeToBezierForm(); - - // Update control points - updateControlPoints(A); -} - -// Computes knot averages: assumes that basis is initialized! -DenseMatrix BSpline::computeKnotAverages() const -{ - // Calculate knot averages for each knot vector - std::vector mu_vectors; - for (unsigned int i = 0; i < numVariables; i++) - { - std::vector knots = basis.getKnotVector(i); - DenseVector mu = DenseVector::Zero(basis.getNumBasisFunctions(i)); - - for (unsigned int j = 0; j < basis.getNumBasisFunctions(i); j++) - { - double knotAvg = 0; - for (unsigned int k = j+1; k <= j+basis.getBasisDegree(i); k++) - { - knotAvg += knots.at(k); - } - mu(j) = knotAvg/basis.getBasisDegree(i); - } - mu_vectors.push_back(mu); - } - - // Calculate vectors of ones (with same length as corresponding knot average vector) - std::vector knotOnes; - for (unsigned int i = 0; i < numVariables; i++) - knotOnes.push_back(DenseVector::Ones(mu_vectors.at(i).rows())); - - // Fill knot average matrix one column at the time - DenseMatrix knot_averages = DenseMatrix::Zero(basis.getNumBasisFunctions(), numVariables); - - for (unsigned int i = 0; i < numVariables; i++) - { - DenseMatrix mu_ext(1,1); mu_ext(0,0) = 1; - for (unsigned int j = 0; j < numVariables; j++) - { - DenseMatrix temp = mu_ext; - if (i == j) - mu_ext = Eigen::kroneckerProduct(temp, mu_vectors.at(j)); - else - mu_ext = Eigen::kroneckerProduct(temp, knotOnes.at(j)); - } - if (mu_ext.rows() != basis.getNumBasisFunctions()) - throw Exception("BSpline::computeKnotAverages: Incompatible size of knot average matrix."); - knot_averages.block(0, i, basis.getNumBasisFunctions(), 1) = mu_ext; - } - - return knot_averages; -} - -void BSpline::insertKnots(double tau, unsigned int dim, unsigned int multiplicity) -{ - // Insert knots and compute knot insertion matrix - SparseMatrix A = basis.insertKnots(tau, dim, multiplicity); - - // Update control points - updateControlPoints(A); -} - -void BSpline::regularizeKnotVectors(std::vector &lb, std::vector &ub) -{ - // Add and remove controlpoints and knots to make the b-spline p-regular with support [lb, ub] - if (!(lb.size() == numVariables && ub.size() == numVariables)) - throw Exception("BSpline::regularizeKnotVectors: Inconsistent vector sizes."); - - for (unsigned int dim = 0; dim < numVariables; dim++) - { - unsigned int multiplicityTarget = basis.getBasisDegree(dim) + 1; - - // Inserting many knots at the time (to save number of B-spline coefficient calculations) - // NOTE: This method generates knot insertion matrices with more nonzero elements than - // the method that inserts one knot at the time. This causes the preallocation of - // kronecker product matrices to become too small and the speed deteriorates drastically - // in higher dimensions because reallocation is necessary. This can be prevented by - // precomputing the number of nonzeros when preallocating memory (see myKroneckerProduct). - int numKnotsLB = multiplicityTarget - basis.getKnotMultiplicity(dim, lb.at(dim)); - if (numKnotsLB > 0) - { - insertKnots(lb.at(dim), dim, numKnotsLB); - } - - int numKnotsUB = multiplicityTarget - basis.getKnotMultiplicity(dim, ub.at(dim)); - if (numKnotsUB > 0) - { - insertKnots(ub.at(dim), dim, numKnotsUB); - } - } -} - -bool BSpline::removeUnsupportedBasisFunctions(std::vector &lb, std::vector &ub) -{ - if (lb.size() != numVariables || ub.size() != numVariables) - throw Exception("BSpline::removeUnsupportedBasisFunctions: Incompatible dimension of domain bounds."); - - SparseMatrix A = basis.reduceSupport(lb, ub); - - if (coefficients.size() != A.rows()) - return false; - - // Remove unsupported control points (basis functions) - updateControlPoints(A.transpose()); - - return true; -} - -void BSpline::save(const std::string &fileName) const -{ - Serializer s; - s.serialize(*this); - s.saveToFile(fileName); -} - -void BSpline::load(const std::string &fileName) -{ - Serializer s(fileName); - s.deserialize(*this); -} - -std::string BSpline::getDescription() const -{ - std::string description("BSpline of degree"); - auto degrees = getBasisDegrees(); - // See if all degrees are the same. - bool equal = true; - for (size_t i = 1; i < degrees.size(); ++i) - { - equal = equal && (degrees.at(i) == degrees.at(i-1)); - } - - if(equal) - { - description.append(" "); - description.append(std::to_string(degrees.at(0))); - } - else - { - description.append("s ("); - for (size_t i = 0; i < degrees.size(); ++i) - { - description.append(std::to_string(degrees.at(i))); - if (i + 1 < degrees.size()) - { - description.append(", "); - } - } - description.append(")"); - } - - return description; -} - -} // namespace SPLINTER diff --git a/splinter/bspline.h b/splinter/bspline.h deleted file mode 100644 index eb72dc8000..0000000000 --- a/splinter/bspline.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -#ifndef SPLINTER_BSPLINE_H -#define SPLINTER_BSPLINE_H - -#include "function.h" -#include "bsplinebasis.h" - -namespace SPLINTER -{ - -/** - * Class that implements the multivariate tensor product B-spline - */ -class SPLINTER_API BSpline : public Function -{ -public: - /** - * Builder class for construction by regression - * Implemented in BSplineBuilder.* - */ - class Builder; - enum class Smoothing; - enum class KnotSpacing; - - BSpline(unsigned int numVariables); - - /** - * Construct B-spline from knot vectors, coefficients, and basis degrees - */ - BSpline(std::vector< std::vector > knotVectors, std::vector basisDegrees); - BSpline(std::vector coefficients, std::vector< std::vector > knotVectors, std::vector basisDegrees); - BSpline(DenseVector coefficients, std::vector< std::vector > knotVectors, std::vector basisDegrees); - - /** - * Construct B-spline from file - */ - BSpline(const char *fileName); - BSpline(const std::string &fileName); - - virtual BSpline* clone() const { return new BSpline(*this); } - - /** - * Evaluation of B-spline - */ - - // Avoid name hiding - using Function::eval; - using Function::evalJacobian; - using Function::evalHessian; - - // Evaluation of B-spline - double eval(DenseVector x) const override; - DenseMatrix evalJacobian(DenseVector x) const override; - DenseMatrix evalHessian(DenseVector x) const override; - - // Evaluation of B-spline basis functions - SparseVector evalBasis(DenseVector x) const; - SparseMatrix evalBasisJacobian(DenseVector x) const; - - /** - * Getters - */ - DenseVector getCoefficients() - { - return coefficients; - } - - unsigned int getNumCoefficients() const - { - return (unsigned int)coefficients.size(); - } - - unsigned int getNumControlPoints() const - { - return (unsigned int)coefficients.size(); - } - - std::vector getNumBasisFunctionsPerVariable() const; - - unsigned int getNumBasisFunctions() const - { - return basis.getNumBasisFunctions(); - } - - DenseMatrix getControlPoints() const; - std::vector< std::vector> getKnotVectors() const; - std::vector getBasisDegrees() const; - std::vector getDomainUpperBound() const; - std::vector getDomainLowerBound() const; - - /** - * Setters - */ - void setCoefficients(const DenseVector &coefficients); - void setControlPoints(const DenseMatrix &controlPoints); - void checkControlPoints() const; - - // Linear transformation of control points (B-spline has affine invariance) - void updateControlPoints(const DenseMatrix &A); - - // Reduce support of B-spline - void reduceSupport(std::vector lb, std::vector ub, bool doRegularizeKnotVectors = true); - - // Perform global knot refinement - void globalKnotRefinement(); // All knots in one shabang - - // Perform a local knot refinement at x - void localKnotRefinement(DenseVector x); - - // Decompose B-spline to Bezier form - void decomposeToBezierForm(); - - // Insert a knot until desired knot multiplicity is obtained - void insertKnots(double tau, unsigned int dim, unsigned int multiplicity = 1); - - void save(const std::string &fileName) const override; - - std::string getDescription() const override; - BSpline(); - -protected: - - BSplineBasis basis; - - /* - * The control point matrix is P = (knotaverages, coefficients) in R^(m x n), - * where m = numBasisFunctions and n = numVariables + 1. Each row in P is a control point. - */ - DenseVector coefficients; - DenseMatrix knotaverages; - - // Control point computations - DenseMatrix computeKnotAverages() const; - -private: - // Domain reduction - void regularizeKnotVectors(std::vector &lb, std::vector &ub); - bool removeUnsupportedBasisFunctions(std::vector &lb, std::vector &ub); - - // Helper functions - bool pointInDomain(DenseVector x) const; - - void load(const std::string &fileName) override; - - friend class Serializer; - friend bool operator==(const BSpline &lhs, const BSpline &rhs); -}; - -} // namespace SPLINTER - -#endif // SPLINTER_BSPLINE_H diff --git a/splinter/bsplinebasis.cpp b/splinter/bsplinebasis.cpp deleted file mode 100644 index c90bbd6ea9..0000000000 --- a/splinter/bsplinebasis.cpp +++ /dev/null @@ -1,468 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -#include "bsplinebasis.h" -#include "mykroneckerproduct.h" -#include "unsupported/Eigen/KroneckerProduct" - -#include - -namespace SPLINTER -{ - -BSplineBasis::BSplineBasis() -{ -} - -BSplineBasis::BSplineBasis(std::vector< std::vector > &knotVectors, std::vector basisDegrees) - : numVariables(knotVectors.size()) -{ - if (knotVectors.size() != basisDegrees.size()) - throw Exception("BSplineBasis::BSplineBasis: Incompatible sizes. Number of knot vectors is not equal to size of degree vector."); - - // Set univariate bases - bases.clear(); - for (unsigned int i = 0; i < numVariables; i++) - { - bases.push_back(BSplineBasis1D(knotVectors.at(i), basisDegrees.at(i))); - - // Adjust target number of basis functions used in e.g. refinement - if (numVariables > 2) - { - // One extra knot is allowed - bases.at(i).setNumBasisFunctionsTarget((basisDegrees.at(i)+1)+1); // Minimum degree+1 - } - } -} - -SparseVector BSplineBasis::eval(const DenseVector &x) const -{ - // Evaluate basisfunctions for each variable i and compute the tensor product of the function values - std::vector basisFunctionValues; - - for (int var = 0; var < x.size(); var++) - basisFunctionValues.push_back(bases.at(var).eval(x(var))); - - return kroneckerProductVectors(basisFunctionValues); -} - -// Old implementation of Jacobian -DenseMatrix BSplineBasis::evalBasisJacobianOld(DenseVector &x) const -{ - // Jacobian basis matrix - DenseMatrix J; J.setZero(getNumBasisFunctions(), numVariables); - - // Calculate partial derivatives - for (unsigned int i = 0; i < numVariables; i++) - { - // One column in basis jacobian - DenseVector bi; bi.setOnes(1); - for (unsigned int j = 0; j < numVariables; j++) - { - DenseVector temp = bi; - DenseVector xi; - if (j == i) - { - // Differentiated basis - xi = bases.at(j).evalFirstDerivative(x(j)); - } - else - { - // Normal basis - xi = bases.at(j).eval(x(j)); - } - - bi = kroneckerProduct(temp, xi); - } - - // Fill out column - J.block(0,i,bi.rows(),1) = bi.block(0,0,bi.rows(),1); - } - - return J; -} - -// NOTE: does not pass tests -SparseMatrix BSplineBasis::evalBasisJacobian(DenseVector &x) const -{ - // Jacobian basis matrix - SparseMatrix J(getNumBasisFunctions(), numVariables); - //J.setZero(numBasisFunctions(), numInputs); - - // Calculate partial derivatives - for (unsigned int i = 0; i < numVariables; ++i) - { - // One column in basis jacobian - std::vector values(numVariables); - - for (unsigned int j = 0; j < numVariables; ++j) - { - if (j == i) - { - // Differentiated basis - values.at(j) = bases.at(j).evalDerivative(x(j), 1); - } - else - { - // Normal basis - values.at(j) = bases.at(j).eval(x(j)); - } - } - - SparseVector Ji = kroneckerProductVectors(values); - - // Fill out column - for (int k = 0; k < Ji.outerSize(); ++k) - for (SparseMatrix::InnerIterator it(Ji,k); it; ++it) - { - if (it.value() != 0) - J.insert(it.row(),i) = it.value(); - } - //J.block(0,i,Ji.rows(),1) = bi.block(0,0,Ji.rows(),1); - } - - J.makeCompressed(); - - return J; -} - -SparseMatrix BSplineBasis::evalBasisJacobian2(DenseVector &x) const -{ - // Jacobian basis matrix - SparseMatrix J(getNumBasisFunctions(), numVariables); - - // Evaluate B-spline basis functions before looping - std::vector funcValues(numVariables); - std::vector gradValues(numVariables); - - for (unsigned int i = 0; i < numVariables; ++i) - { - funcValues[i] = bases.at(i).eval(x(i)); - gradValues[i] = bases.at(i).evalFirstDerivative(x(i)); - } - - // Calculate partial derivatives - for (unsigned int i = 0; i < numVariables; i++) - { - std::vector values(numVariables); - - for (unsigned int j = 0; j < numVariables; j++) - { - if (j == i) - values.at(j) = gradValues.at(j); // Differentiated basis - else - values.at(j) = funcValues.at(j); // Normal basis - } - - SparseVector Ji = kroneckerProductVectors(values); - - // Fill out column - for (SparseVector::InnerIterator it(Ji); it; ++it) - J.insert(it.row(),i) = it.value(); - } - - return J; -} - -SparseMatrix BSplineBasis::evalBasisHessian(DenseVector &x) const -{ - // Hessian basis matrix - /* Hij = B1 x ... x DBi x ... x DBj x ... x Bn - * (Hii = B1 x ... x DDBi x ... x Bn) - * Where B are basis functions evaluated at x, - * DB are the derivative of the basis functions, - * and x is the kronecker product. - * Hij is in R^(numBasisFunctions x 1) - * so that basis hessian H is in R^(numBasisFunctions*numInputs x numInputs) - * The real B-spline Hessian is calculated as (c^T x 1^(numInputs x 1))*H - */ - SparseMatrix H(getNumBasisFunctions()*numVariables, numVariables); - //H.setZero(numBasisFunctions()*numInputs, numInputs); - - // Calculate partial derivatives - // Utilizing that Hessian is symmetric - // Filling out lower left triangular - for (unsigned int i = 0; i < numVariables; i++) // row - { - for (unsigned int j = 0; j <= i; j++) // col - { - // One column in basis jacobian - SparseMatrix Hi(1,1); - Hi.insert(0,0) = 1; - - for (unsigned int k = 0; k < numVariables; k++) - { - SparseMatrix temp = Hi; - SparseMatrix Bk; - if (i == j && k == i) - { - // Diagonal element - Bk = bases.at(k).evalDerivative(x(k), 2); - } - else if (k == i || k == j) - { - Bk = bases.at(k).evalDerivative(x(k), 1); - } - else - { - Bk = bases.at(k).eval(x(k)); - } - Hi = kroneckerProduct(temp, Bk); - } - - // Fill out column - for (int k = 0; k < Hi.outerSize(); ++k) - for (SparseMatrix::InnerIterator it(Hi,k); it; ++it) - { - if (it.value() != 0) - { - int row = i*getNumBasisFunctions()+it.row(); - int col = j; - H.insert(row,col) = it.value(); - } - } - } - } - - H.makeCompressed(); - - return H; -} - -SparseMatrix BSplineBasis::insertKnots(double tau, unsigned int dim, unsigned int multiplicity) -{ - SparseMatrix A(1,1); -// A.resize(1,1); - A.insert(0,0) = 1; - - // Calculate multivariate knot insertion matrix - for (unsigned int i = 0; i < numVariables; i++) - { - SparseMatrix temp = A; - SparseMatrix Ai; - - if (i == dim) - { - // Build knot insertion matrix - Ai = bases.at(i).insertKnots(tau, multiplicity); - } - else - { - // No insertion - identity matrix - int m = bases.at(i).getNumBasisFunctions(); - Ai.resize(m,m); - Ai.setIdentity(); - } - - //A = kroneckerProduct(temp, Ai); - A = myKroneckerProduct(temp, Ai); - } - - A.makeCompressed(); - - return A; -} - -SparseMatrix BSplineBasis::refineKnots() -{ - SparseMatrix A(1,1); - A.insert(0,0) = 1; - - for (unsigned int i = 0; i < numVariables; i++) - { - SparseMatrix temp = A; - SparseMatrix Ai = bases.at(i).refineKnots(); - - //A = kroneckerProduct(temp, Ai); - A = myKroneckerProduct(temp, Ai); - } - - A.makeCompressed(); - - return A; -} - -SparseMatrix BSplineBasis::refineKnotsLocally(DenseVector x) -{ - SparseMatrix A(1,1); - A.insert(0,0) = 1; - - for (unsigned int i = 0; i < numVariables; i++) - { - SparseMatrix temp = A; - SparseMatrix Ai = bases.at(i).refineKnotsLocally(x(i)); - - //A = kroneckerProduct(temp, Ai); - A = myKroneckerProduct(temp, Ai); - } - - A.makeCompressed(); - - return A; -} - -SparseMatrix BSplineBasis::decomposeToBezierForm() -{ - SparseMatrix A(1,1); - A.insert(0,0) = 1; - - for (unsigned int i = 0; i < numVariables; i++) - { - SparseMatrix temp = A; - SparseMatrix Ai = bases.at(i).decomposeToBezierForm(); - - //A = kroneckerProduct(temp, Ai); - A = myKroneckerProduct(temp, Ai); - } - - A.makeCompressed(); - - return A; -} - -SparseMatrix BSplineBasis::reduceSupport(std::vector& lb, std::vector& ub) -{ - if (lb.size() != ub.size() || lb.size() != numVariables) - throw Exception("BSplineBasis::reduceSupport: Incompatible dimension of domain bounds."); - - SparseMatrix A(1,1); - A.insert(0,0) = 1; - - for (unsigned int i = 0; i < numVariables; i++) - { - SparseMatrix temp = A; - SparseMatrix Ai; - - Ai = bases.at(i).reduceSupport(lb.at(i), ub.at(i)); - - //A = kroneckerProduct(temp, Ai); - A = myKroneckerProduct(temp, Ai); - } - - A.makeCompressed(); - - return A; -} - -std::vector BSplineBasis::getBasisDegrees() const -{ - std::vector degrees; - for (const auto& basis : bases) - degrees.push_back(basis.getBasisDegree()); - return degrees; -} - -unsigned int BSplineBasis::getBasisDegree(unsigned int dim) const -{ - return bases.at(dim).getBasisDegree(); -} - -unsigned int BSplineBasis::getNumBasisFunctions(unsigned int dim) const -{ - return bases.at(dim).getNumBasisFunctions(); -} - -unsigned int BSplineBasis::getNumBasisFunctions() const -{ - unsigned int prod = 1; - for (unsigned int dim = 0; dim < numVariables; dim++) - { - prod *= bases.at(dim).getNumBasisFunctions(); - } - return prod; -} - -BSplineBasis1D BSplineBasis::getSingleBasis(int dim) -{ - return bases.at(dim); -} - -std::vector BSplineBasis::getKnotVector(int dim) const -{ - return bases.at(dim).getKnotVector(); -} - -std::vector< std::vector > BSplineBasis::getKnotVectors() const -{ - std::vector< std::vector > knots; - for (unsigned int i = 0; i < numVariables; i++) - knots.push_back(bases.at(i).getKnotVector()); - return knots; -} - -unsigned int BSplineBasis::getKnotMultiplicity(unsigned int dim, double tau) const -{ - return bases.at(dim).knotMultiplicity(tau); -} - -double BSplineBasis::getKnotValue(int dim, int index) const -{ - return bases.at(dim).getKnotValue(index); -} - -unsigned int BSplineBasis::getLargestKnotInterval(unsigned int dim) const -{ - return bases.at(dim).indexLongestInterval(); -} - -std::vector BSplineBasis::getNumBasisFunctionsTarget() const -{ - std::vector ret; - for (unsigned int dim = 0; dim < numVariables; dim++) - { - ret.push_back(bases.at(dim).getNumBasisFunctionsTarget() ); - } - return ret; -} - -int BSplineBasis::supportedPrInterval() const -{ - int ret = 1; - for (unsigned int dim = 0; dim < numVariables; dim++) - { - ret *= (bases.at(dim).getBasisDegree() + 1); - } - return ret; -} - -bool BSplineBasis::insideSupport(DenseVector &x) const -{ - for (unsigned int dim = 0; dim < numVariables; dim++) - { - if (!bases.at(dim).insideSupport(x(dim))) - { - return false; - } - } - return true; -} - -std::vector BSplineBasis::getSupportLowerBound() const -{ - std::vector lb; - for (unsigned int dim = 0; dim < numVariables; dim++) - { - std::vector knots = bases.at(dim).getKnotVector(); - lb.push_back(knots.front()); - } - return lb; -} - -std::vector BSplineBasis::getSupportUpperBound() const -{ - std::vector ub; - for (unsigned int dim = 0; dim < numVariables; dim++) - { - std::vector knots = bases.at(dim).getKnotVector(); - ub.push_back(knots.back()); - } - return ub; -} - -} // namespace SPLINTER diff --git a/splinter/bsplinebasis.h b/splinter/bsplinebasis.h deleted file mode 100644 index 039c8d44fb..0000000000 --- a/splinter/bsplinebasis.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -#ifndef SPLINTER_BSPLINEBASIS_H -#define SPLINTER_BSPLINEBASIS_H - -#include "definitions.h" -#include "bsplinebasis1d.h" - -namespace SPLINTER -{ - -class BSplineBasis -{ -public: - BSplineBasis(); - BSplineBasis(std::vector> &knotVectors, std::vector basisDegrees); - - // Evaluation - SparseVector eval(const DenseVector &x) const; - DenseMatrix evalBasisJacobianOld(DenseVector &x) const; // Depricated - SparseMatrix evalBasisJacobian(DenseVector &x) const; - SparseMatrix evalBasisJacobian2(DenseVector &x) const; // A bit slower than evaBasisJacobianOld() - SparseMatrix evalBasisHessian(DenseVector &x) const; - - // Knot vector manipulation - SparseMatrix refineKnots(); - SparseMatrix refineKnotsLocally(DenseVector x); - SparseMatrix decomposeToBezierForm(); - SparseMatrix insertKnots(double tau, unsigned int dim, unsigned int multiplicity = 1); - - // Getters - BSplineBasis1D getSingleBasis(int dim); - std::vector< std::vector > getKnotVectors() const; - std::vector getKnotVector(int dim) const; - - std::vector getBasisDegrees() const; - unsigned int getBasisDegree(unsigned int dim) const; - unsigned int getNumBasisFunctions() const; - unsigned int getNumBasisFunctions(unsigned int dim) const; - std::vector getNumBasisFunctionsTarget() const; - - double getKnotValue(int dim, int index) const; - unsigned int getKnotMultiplicity(unsigned int dim, double tau) const; - unsigned int getLargestKnotInterval(unsigned int dim) const; - - int supportedPrInterval() const; - - bool insideSupport(DenseVector &x) const; - std::vector getSupportLowerBound() const; - std::vector getSupportUpperBound() const; - - // Support related - SparseMatrix reduceSupport(std::vector& lb, std::vector& ub); - -private: - std::vector bases; - unsigned int numVariables; - - friend class Serializer; - friend bool operator==(const BSplineBasis &lhs, const BSplineBasis &rhs); -}; - -} // namespace SPLINTER - -#endif // SPLINTER_BSPLINEBASIS_H diff --git a/splinter/bsplinebasis1d.cpp b/splinter/bsplinebasis1d.cpp deleted file mode 100644 index 2494d6b711..0000000000 --- a/splinter/bsplinebasis1d.cpp +++ /dev/null @@ -1,607 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ -#include -#include - -#include "bsplinebasis1d.h" -#include "knots.h" -#include "utilities.h" - -namespace SPLINTER -{ - -BSplineBasis1D::BSplineBasis1D() -{ -} - -BSplineBasis1D::BSplineBasis1D(const std::vector &knots, unsigned int degree) - : degree(degree), - knots(knots), - targetNumBasisfunctions((degree+1)+2*degree+1) // Minimum p+1 -{ -// if (degree <= 0) -// throw Exception("BSplineBasis1D::BSplineBasis1D: Cannot create B-spline basis functions of degree <= 0."); - - if (!isKnotVectorRegular(knots, degree)) - throw Exception("BSplineBasis1D::BSplineBasis1D: Knot vector is not regular."); -} - -SparseVector BSplineBasis1D::eval(double x) const -{ - SparseVector values(getNumBasisFunctions()); - - if (!insideSupport(x)) - return values; - - supportHack(x); - - std::vector indexSupported = indexSupportedBasisfunctions(x); - - values.reserve(indexSupported.size()); - - // Evaluate nonzero basis functions - for (auto it = indexSupported.begin(); it != indexSupported.end(); ++it) - { - double val = deBoorCox(x, *it, degree); - if (std::abs(val) > 1e-12) - values.insert(*it) = val; - } - - // Alternative evaluation using basis matrix -// int knotIndex = indexHalfopenInterval(x); // knot index - -// SparseMatrix basisvalues2 = buildBsplineMatrix(x, knotIndex, 1); -// for (int i = 2; i <= basisDegree; i++) -// { -// SparseMatrix Ri = buildBsplineMatrix(x, knotIndex, i); -// basisvalues2 = basisvalues2*Ri; -// } -// basisvalues2.makeCompressed(); - -// assert(basisvalues2.rows() == 1); -// assert(basisvalues2.cols() == basisDegree + 1); - - return values; -} - -SparseVector BSplineBasis1D::evalDerivative(double x, int r) const -{ - // Evaluate rth derivative of basis functions at x - // Returns vector [D^(r)B_(u-p,p)(x) ... D^(r)B_(u,p)(x)] - // where u is the knot index and p is the degree - int p = degree; - - // Continuity requirement - //assert(p > r); - if (p <= r) - { - // Return zero-gradient - SparseVector DB(getNumBasisFunctions()); - return DB; - } - - // Check for knot multiplicity here! - - supportHack(x); - - int knotIndex = indexHalfopenInterval(x); - - // Algorithm 3.18 from Lyche and Moerken (2011) - SparseMatrix B(1,1); - B.insert(0,0) = 1; - - for (int i = 1; i <= p-r; i++) - { - SparseMatrix R = buildBasisMatrix(x, knotIndex, i); - B = B*R; - } - - for (int i = p-r+1; i <= p; i++) - { - SparseMatrix DR = buildBasisMatrix(x, knotIndex, i, true); - B = B*DR; - } - double factorial = std::tgamma(p+1)/std::tgamma(p-r+1); - B = B*factorial; - - if (B.cols() != p+1) - throw Exception("BSplineBasis1D::evalDerivative: Wrong number of columns of B matrix."); - - // From row vector to extended column vector - SparseVector DB(getNumBasisFunctions()); - DB.reserve(p+1); - int i = knotIndex-p; // First insertion index - for (int k = 0; k < B.outerSize(); ++k) - for (SparseMatrix::InnerIterator it(B,k); it; ++it) - { - DB.insert(i+it.col()) = it.value(); - } - - return DB; -} - -// Old implementation of first derivative of basis functions -SparseVector BSplineBasis1D::evalFirstDerivative(double x) const -{ - SparseVector values(getNumBasisFunctions()); - - supportHack(x); - - std::vector supportedBasisFunctions = indexSupportedBasisfunctions(x); - - for (int i : supportedBasisFunctions) - { - // Differentiate basis function - // Equation 3.35 in Lyche & Moerken (2011) - double b1 = deBoorCox(x, i, degree-1); - double b2 = deBoorCox(x, i+1, degree-1); - - double t11 = knots.at(i); - double t12 = knots.at(i+degree); - double t21 = knots.at(i+1); - double t22 = knots.at(i+degree+1); - - (t12 == t11) ? b1 = 0 : b1 = b1/(t12-t11); - (t22 == t21) ? b2 = 0 : b2 = b2/(t22-t21); - - values.insert(i) = degree*(b1 - b2); - } - - return values; -} - -// Used to evaluate basis functions - alternative to the recursive deBoorCox -SparseMatrix BSplineBasis1D::buildBasisMatrix(double x, unsigned int u, unsigned int k, bool diff) const -{ - /* Build B-spline Matrix - * R_k in R^(k,k+1) - * or, if diff = true, the differentiated basis matrix - * DR_k in R^(k,k+1) - */ - - if (!(k >= 1 && k <= getBasisDegree())) - { - throw Exception("BSplineBasis1D::buildBasisMatrix: Incorrect input paramaters!"); - } - -// assert(u >= basisDegree + 1); -// assert(u < ks.size() - basisDegree); - - unsigned int rows = k; - unsigned int cols = k+1; - SparseMatrix R(rows, cols); - R.reserve(Eigen::VectorXi::Constant(cols, 2)); - - for (unsigned int i = 0; i < rows; i++) - { - double dk = knots.at(u+1+i) - knots.at(u+1+i-k); - if (dk == 0) - { - continue; - } - else - { - if (diff) - { - // Insert diagonal element - R.insert(i,i) = -1/dk; - - // Insert super-diagonal element - R.insert(i,i+1) = 1/dk; - } - else - { - // Insert diagonal element - double a = (knots.at(u+1+i) - x)/dk; - if (a != 0) - R.insert(i,i) = a; - - // Insert super-diagonal element - double b = (x - knots.at(u+1+i-k))/dk; - if (b != 0) - R.insert(i,i+1) = b; - } - } - } - - R.makeCompressed(); - - return R; -} - -double BSplineBasis1D::deBoorCox(double x, int i, int k) const -{ - if (k == 0) - { - if (inHalfopenInterval(x, knots.at(i), knots.at(i+1))) - return 1; - else - return 0; - } - else - { - double s1,s2,r1,r2; - - s1 = deBoorCoxCoeff(x, knots.at(i), knots.at(i+k)); - s2 = deBoorCoxCoeff(x, knots.at(i+1), knots.at(i+k+1)); - - r1 = deBoorCox(x, i, k-1); - r2 = deBoorCox(x, i+1, k-1); - - return s1*r1 + (1-s2)*r2; - } -} - -double BSplineBasis1D::deBoorCoxCoeff(double x, double x_min, double x_max) const -{ - if (x_min < x_max && x_min <= x && x <= x_max) - return (x - x_min)/(x_max - x_min); - return 0; -} - -// Insert knots and compute knot insertion matrix (to update control points) -SparseMatrix BSplineBasis1D::insertKnots(double tau, unsigned int multiplicity) -{ - if (!insideSupport(tau)) - throw Exception("BSplineBasis1D::insertKnots: Cannot insert knot outside domain!"); - - if (knotMultiplicity(tau) + multiplicity > degree + 1) - throw Exception("BSplineBasis1D::insertKnots: Knot multiplicity is too high!"); - - // New knot vector - int index = indexHalfopenInterval(tau); - - std::vector extKnots = knots; - for (unsigned int i = 0; i < multiplicity; i++) - extKnots.insert(extKnots.begin()+index+1, tau); - - if (!isKnotVectorRegular(extKnots, degree)) - throw Exception("BSplineBasis1D::insertKnots: New knot vector is not regular!"); - - // Return knot insertion matrix - SparseMatrix A = buildKnotInsertionMatrix(extKnots); - - // Update knots - knots = extKnots; - - return A; -} - -SparseMatrix BSplineBasis1D::refineKnots() -{ - // Build refine knot vector - std::vector refinedKnots = knots; - - unsigned int targetNumKnots = targetNumBasisfunctions + degree + 1; - while (refinedKnots.size() < targetNumKnots) - { - int index = indexLongestInterval(refinedKnots); - double newKnot = (refinedKnots.at(index) + refinedKnots.at(index+1))/2.0; - refinedKnots.insert(std::lower_bound(refinedKnots.begin(), refinedKnots.end(), newKnot), newKnot); - } - - if (!isKnotVectorRegular(refinedKnots, degree)) - throw Exception("BSplineBasis1D::refineKnots: New knot vector is not regular!"); - - if (!isKnotVectorRefinement(knots, refinedKnots)) - throw Exception("BSplineBasis1D::refineKnots: New knot vector is not a proper refinement!"); - - // Return knot insertion matrix - SparseMatrix A = buildKnotInsertionMatrix(refinedKnots); - - // Update knots - knots = refinedKnots; - - return A; -} - -SparseMatrix BSplineBasis1D::refineKnotsLocally(double x) -{ - if (!insideSupport(x)) - throw Exception("BSplineBasis1D::refineKnotsLocally: Cannot refine outside support!"); - - if (getNumBasisFunctions() >= getNumBasisFunctionsTarget() - || assertNear(knots.front(), knots.back())) - { - unsigned int n = getNumBasisFunctions(); - DenseMatrix A = DenseMatrix::Identity(n,n); - return A.sparseView(); - } - - // Refined knot vector - std::vector refinedKnots = knots; - - auto upper = std::lower_bound(refinedKnots.begin(), refinedKnots.end(), x); - - // Check left boundary - if (upper == refinedKnots.begin()) - std::advance(upper, degree+1); - - // Get previous iterator - auto lower = std::prev(upper); - - // Do not insert if upper and lower bounding knot are close - if (assertNear(*upper, *lower)) - { - unsigned int n = getNumBasisFunctions(); - DenseMatrix A = DenseMatrix::Identity(n,n); - return A.sparseView(); - } - - // Insert knot at x - double insertVal = x; - - // Adjust x if it is on or close to a knot - if (knotMultiplicity(x) > 0 - || assertNear(*upper, x, 1e-6, 1e-6) - || assertNear(*lower, x, 1e-6, 1e-6)) - { - insertVal = (*upper + *lower)/2.0; - } - - // Insert new knot - refinedKnots.insert(upper, insertVal); - - if (!isKnotVectorRegular(refinedKnots, degree)) - throw Exception("BSplineBasis1D::refineKnotsLocally: New knot vector is not regular!"); - - if (!isKnotVectorRefinement(knots, refinedKnots)) - throw Exception("BSplineBasis1D::refineKnotsLocally: New knot vector is not a proper refinement!"); - - // Build knot insertion matrix - SparseMatrix A = buildKnotInsertionMatrix(refinedKnots); - - // Update knots - knots = refinedKnots; - - return A; -} - -SparseMatrix BSplineBasis1D::decomposeToBezierForm() -{ - // Build refine knot vector - std::vector refinedKnots = knots; - - // Start at first knot and add knots until all knots have multiplicity degree + 1 - std::vector::iterator knoti = refinedKnots.begin(); - while (knoti != refinedKnots.end()) - { - // Insert new knots - int mult = degree + 1 - knotMultiplicity(*knoti); - if (mult > 0) - { - std::vector newKnots(mult, *knoti); - refinedKnots.insert(knoti, newKnots.begin(), newKnots.end()); - } - - // Advance to next knot - knoti = std::upper_bound(refinedKnots.begin(), refinedKnots.end(), *knoti); - } - - if (!isKnotVectorRegular(refinedKnots, degree)) - throw Exception("BSplineBasis1D::refineKnots: New knot vector is not regular!"); - - if (!isKnotVectorRefinement(knots, refinedKnots)) - throw Exception("BSplineBasis1D::refineKnots: New knot vector is not a proper refinement!"); - - // Return knot insertion matrix - SparseMatrix A = buildKnotInsertionMatrix(refinedKnots); - - // Update knots - knots = refinedKnots; - - return A; -} - -SparseMatrix BSplineBasis1D::buildKnotInsertionMatrix(const std::vector &refinedKnots) const -{ - if (!isKnotVectorRegular(refinedKnots, degree)) - throw Exception("BSplineBasis1D::buildKnotInsertionMatrix: New knot vector is not regular!"); - - if (!isKnotVectorRefinement(knots, refinedKnots)) - throw Exception("BSplineBasis1D::buildKnotInsertionMatrix: New knot vector is not a proper refinement!"); - - std::vector knotsAug = refinedKnots; - unsigned int n = knots.size() - degree - 1; - unsigned int m = knotsAug.size() - degree - 1; - - SparseMatrix A(m, n); - //A.resize(m,n); - A.reserve(Eigen::VectorXi::Constant(n, degree + 1)); - - // Build A row-by-row - for (unsigned int i = 0; i < m; i++) - { - int u = indexHalfopenInterval(knotsAug.at(i)); - - SparseMatrix R(1,1); - R.insert(0,0) = 1; - - // For p > 0 - for (unsigned int j = 1; j <= degree; j++) - { - SparseMatrix Ri = buildBasisMatrix(knotsAug.at(i + j), u, j); - R = R*Ri; - } - - // Size check - if (R.rows() != 1 || R.cols() != (int)degree + 1) - { - throw Exception("BSplineBasis1D::buildKnotInsertionMatrix: Incorrect matrix dimensions!"); - } - - // Insert row values - int j = u - degree; // First insertion index - for (int k = 0; k < R.outerSize(); ++k) - for (SparseMatrix::InnerIterator it(R, k); it; ++it) - { - A.insert(i, j + it.col()) = it.value(); - } - } - - A.makeCompressed(); - - return A; -} - -/* - * The B-spline domain is the half-open domain [ knots.first(), knots.end() ). - * The hack checks if x is at the right boundary (if x = knots.end()), if so, - * a small number is subtracted from x, moving x into the half-open domain. - */ -void BSplineBasis1D::supportHack(double &x) const -{ - if (x == knots.back()) - x = std::nextafter(x, std::numeric_limits::lowest()); -} - -/* - * Finds index i such that knots.at(i) <= x < knots.at(i+1). - * Returns false if x is outside support. - */ -int BSplineBasis1D::indexHalfopenInterval(double x) const -{ - if (x < knots.front() || x > knots.back()) - throw Exception("BSplineBasis1D::indexHalfopenInterval: x outside knot interval!"); - - // Find first knot that is larger than x - std::vector::const_iterator it = std::upper_bound(knots.begin(), knots.end(), x); - - // Return index - int index = it - knots.begin(); - return index - 1; -} - -SparseMatrix BSplineBasis1D::reduceSupport(double lb, double ub) -{ - // Check bounds - if (lb < knots.front() || ub > knots.back()) - throw Exception("BSplineBasis1D::reduceSupport: Cannot increase support!"); - - unsigned int k = degree + 1; - - int index_lower = indexSupportedBasisfunctions(lb).front(); - int index_upper = indexSupportedBasisfunctions(ub).back(); - - // Check lower bound index - if (k != knotMultiplicity(knots.at(index_lower))) - { - int suggested_index = index_lower - 1; - if (0 <= suggested_index) - { - index_lower = suggested_index; - } - else - { - throw Exception("BSplineBasis1D::reduceSupport: Suggested index is negative!"); - } - } - - // Check upper bound index - if (knotMultiplicity(ub) == k && knots.at(index_upper) == ub) - { - index_upper -= k; - } - - // New knot vector - std::vector si; - si.insert(si.begin(), knots.begin()+index_lower, knots.begin()+index_upper+k+1); - - // Construct selection matrix A - int numOld = knots.size()-k; // Current number of basis functions - int numNew = si.size()-k; // Number of basis functions after update - - if (numOld < numNew) - throw Exception("BSplineBasis1D::reduceSupport: Number of basis functions is increased instead of reduced!"); - - DenseMatrix Ad = DenseMatrix::Zero(numOld, numNew); - Ad.block(index_lower, 0, numNew, numNew) = DenseMatrix::Identity(numNew, numNew); - SparseMatrix A = Ad.sparseView(); - - // Update knots - knots = si; - - return A; -} - -double BSplineBasis1D::getKnotValue(unsigned int index) const -{ - return knots.at(index); -} - -unsigned int BSplineBasis1D::knotMultiplicity(double tau) const -{ - return std::count(knots.begin(), knots.end(), tau); -} - -bool BSplineBasis1D::inHalfopenInterval(double x, double x_min, double x_max) const -{ - return (x_min <= x) && (x < x_max); -} - -bool BSplineBasis1D::insideSupport(double x) const -{ - return (knots.front() <= x) && (x <= knots.back()); -} - -unsigned int BSplineBasis1D::getNumBasisFunctions() const -{ - return knots.size() - (degree + 1); -} - -unsigned int BSplineBasis1D::getNumBasisFunctionsTarget() const -{ - return targetNumBasisfunctions; -} - -// Return indices of supporting basis functions at x -std::vector BSplineBasis1D::indexSupportedBasisfunctions(double x) const -{ - std::vector ret; - if (insideSupport(x)) - { - int last = indexHalfopenInterval(x); - if (last < 0) - { - // NOTE: can this happen? - last = knots.size() - 1 - (degree + 1); - } - int first = std::max((int)(last - degree), 0); - for (int i = first; i <= last; i++) - { - ret.push_back(i); - } - } - return ret; -} - -unsigned int BSplineBasis1D::indexLongestInterval() const -{ - return indexLongestInterval(knots); -} - -unsigned int BSplineBasis1D::indexLongestInterval(const std::vector &vec) const -{ - double longest = 0; - double interval = 0; - unsigned int index = 0; - - for (unsigned int i = 0; i < vec.size() - 1; i++) - { - interval = vec.at(i+1) - vec.at(i); - if (longest < interval) - { - longest = interval; - index = i; - } - } - return index; -} - -} // namespace SPLINTER diff --git a/splinter/bsplinebasis1d.h b/splinter/bsplinebasis1d.h deleted file mode 100644 index 203fb5299c..0000000000 --- a/splinter/bsplinebasis1d.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -#ifndef SPLINTER_BSPLINEBASIS1D_H -#define SPLINTER_BSPLINEBASIS1D_H - -#include "definitions.h" - -namespace SPLINTER -{ - -class BSplineBasis1D -{ -public: - BSplineBasis1D(); - BSplineBasis1D(const std::vector &knots, unsigned int degree); - - // Evaluation of basis functions - SparseVector eval(double x) const; - SparseVector evalDerivative(double x, int r) const; - SparseVector evalFirstDerivative(double x) const; // Depricated - - // Knot vector related - SparseMatrix refineKnots(); - SparseMatrix refineKnotsLocally(double x); - SparseMatrix decomposeToBezierForm(); - SparseMatrix insertKnots(double tau, unsigned int multiplicity = 1); - // bool insertKnots(SparseMatrix &A, std::vector> newKnots); // Add knots at several locations - unsigned int knotMultiplicity(double tau) const; // Returns the number of repetitions of tau in the knot vector - - // Support related - void supportHack(double &x) const; - bool insideSupport(double x) const; - SparseMatrix reduceSupport(double lb, double ub); - - // Getters - std::vector getKnotVector() const { return knots; } - unsigned int getBasisDegree() const { return degree; } - double getKnotValue(unsigned int index) const; - unsigned int getNumBasisFunctions() const; - unsigned int getNumBasisFunctionsTarget() const; - - // Index getters - std::vector indexSupportedBasisfunctions(double x) const; - int indexHalfopenInterval(double x) const; - unsigned int indexLongestInterval() const; - unsigned int indexLongestInterval(const std::vector &vec) const; - - // Setters - void setNumBasisFunctionsTarget(unsigned int target) - { - targetNumBasisfunctions = std::max(degree+1, target); - } - -private: - // DeBoorCox algorithm for evaluating basis functions - double deBoorCox(double x, int i, int k) const; - double deBoorCoxCoeff(double x, double x_min, double x_max) const; - - // Builds basis matrix for alternative evaluation of basis functions - SparseMatrix buildBasisMatrix(double x, unsigned int u, unsigned int k, bool diff = false) const; - - /* - * Builds knot insertion matrix - * Implements Oslo Algorithm 1 from Lyche and Moerken (2011). Spline methods draft. - */ - SparseMatrix buildKnotInsertionMatrix(const std::vector &refinedKnots) const; - - // Helper functions - bool inHalfopenInterval(double x, double x_min, double x_max) const; - - // Member variables - unsigned int degree; - std::vector knots; - unsigned int targetNumBasisfunctions; - - friend class Serializer; - friend bool operator==(const BSplineBasis1D &lhs, const BSplineBasis1D &rhs); - friend bool operator!=(const BSplineBasis1D &lhs, const BSplineBasis1D &rhs); -}; - -} // namespace SPLINTER - -#endif // SPLINTER_BSPLINEBASIS1D_H diff --git a/splinter/bsplinebuilder.cpp b/splinter/bsplinebuilder.cpp deleted file mode 100644 index 9d0c57a4e0..0000000000 --- a/splinter/bsplinebuilder.cpp +++ /dev/null @@ -1,558 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -#include -#include "bsplinebuilder.h" -#include "mykroneckerproduct.h" -#include "unsupported/Eigen/KroneckerProduct" -#include "linearsolvers.h" -#include "serializer.h" -#include "utilities.h" - -namespace SPLINTER -{ -// Default constructor -BSpline::Builder::Builder(const DataTable &data) - : - _data(data), - _degrees(getBSplineDegrees(data.getNumVariables(), 3)), - _numBasisFunctions(std::vector(data.getNumVariables(), 0)), - _knotSpacing(KnotSpacing::AS_SAMPLED), - _smoothing(Smoothing::NONE), - _alpha(0.1) -{ -} - -/* - * Build B-spline - */ -BSpline BSpline::Builder::build() const -{ - // Check data - // TODO: Remove this test - if (!_data.isGridComplete()) - throw Exception("BSpline::Builder::build: Cannot create B-spline from irregular (incomplete) grid."); - - // Build knot vectors - auto knotVectors = computeKnotVectors(); - - // Build B-spline (with default coefficients) - auto bspline = BSpline(knotVectors, _degrees); - - // Compute coefficients from samples and update B-spline - auto coefficients = computeCoefficients(bspline); - bspline.setCoefficients(coefficients); - - return bspline; -} - -/* - * Find coefficients of B-spline by solving: - * min ||A*x - b||^2 + alpha*||R||^2, - * where - * A = mxn matrix of n basis functions evaluated at m sample points, - * b = vector of m sample points y-values (or x-values when calculating knot averages), - * x = B-spline coefficients (or knot averages), - * R = Regularization matrix, - * alpha = regularization parameter. - */ -DenseVector BSpline::Builder::computeCoefficients(const BSpline& bspline) const -{ - SparseMatrix B = computeBasisFunctionMatrix(bspline); - SparseMatrix A = B; - DenseVector b = getSamplePointValues(); - - if (_smoothing == Smoothing::IDENTITY) - { - /* - * Computing B-spline coefficients with a regularization term - * ||Ax-b||^2 + alpha*x^T*x - * - * NOTE: This corresponds to a Tikhonov regularization (or ridge regression) with the Identity matrix. - * See: https://en.wikipedia.org/wiki/Tikhonov_regularization - * - * NOTE2: consider changing regularization factor to (alpha/numSample) - */ - SparseMatrix Bt = B.transpose(); - A = Bt*B; - b = Bt*b; - - auto I = SparseMatrix(A.cols(), A.cols()); - I.setIdentity(); - A += _alpha*I; - } - else if (_smoothing == Smoothing::PSPLINE) - { - /* - * The P-Spline is a smooting B-spline which relaxes the interpolation constraints on the control points to allow - * smoother spline curves. It minimizes an objective which penalizes both deviation from sample points (to lower bias) - * and the magnitude of second derivatives (to lower variance). - * - * Setup and solve equations Ax = b, - * A = B'*W*B + l*D'*D - * b = B'*W*y - * x = control coefficients or knot averages. - * B = basis functions at sample x-values, - * W = weighting matrix for interpolating specific points - * D = second-order finite difference matrix - * l = penalizing parameter (increase for more smoothing) - * y = sample y-values when calculating control coefficients, - * y = sample x-values when calculating knot averages - */ - - // Assuming regular grid - unsigned int numSamples = _data.getNumSamples(); - - SparseMatrix Bt = B.transpose(); - - // Weight matrix - SparseMatrix W; - W.resize(numSamples, numSamples); - W.setIdentity(); - - // Second order finite difference matrix - SparseMatrix D = getSecondOrderFiniteDifferenceMatrix(bspline); - - // Left-hand side matrix - A = Bt*W*B + _alpha*D.transpose()*D; - - // Compute right-hand side matrices - b = Bt*W*b; - } - - DenseVector x; - - int numEquations = A.rows(); - int maxNumEquations = 100; - bool solveAsDense = (numEquations < maxNumEquations); - - if (!solveAsDense) - { -#ifndef NDEBUG - std::cout << "BSpline::Builder::computeBSplineCoefficients: Computing B-spline control points using sparse solver." << std::endl; -#endif // NDEBUG - - SparseLU<> s; - //bool successfulSolve = (s.solve(A,Bx,Cx) && s.solve(A,By,Cy)); - - solveAsDense = !s.solve(A, b, x); - } - - if (solveAsDense) - { -#ifndef NDEBUG - std::cout << "BSpline::Builder::computeBSplineCoefficients: Computing B-spline control points using dense solver." << std::endl; -#endif // NDEBUG - - DenseMatrix Ad = A.toDense(); - DenseQR s; - // DenseSVD s; - //bool successfulSolve = (s.solve(Ad,Bx,Cx) && s.solve(Ad,By,Cy)); - if (!s.solve(Ad, b, x)) - { - throw Exception("BSpline::Builder::computeBSplineCoefficients: Failed to solve for B-spline coefficients."); - } - } - - return x; -} - -SparseMatrix BSpline::Builder::computeBasisFunctionMatrix(const BSpline &bspline) const -{ - unsigned int numVariables = _data.getNumVariables(); - unsigned int numSamples = _data.getNumSamples(); - - // TODO: Reserve nnz per row (degree+1) - //int nnzPrCol = bspline.basis.supportedPrInterval(); - - SparseMatrix A(numSamples, bspline.getNumBasisFunctions()); - //A.reserve(DenseVector::Constant(numSamples, nnzPrCol)); // TODO: should reserve nnz per row! - - int i = 0; - for (auto it = _data.cbegin(); it != _data.cend(); ++it, ++i) - { - DenseVector xi(numVariables); - xi.setZero(); - std::vector xv = it->getX(); - for (unsigned int j = 0; j < numVariables; ++j) - { - xi(j) = xv.at(j); - } - - SparseVector basisValues = bspline.evalBasis(xi); - - for (SparseVector::InnerIterator it2(basisValues); it2; ++it2) - { - A.insert(i,it2.index()) = it2.value(); - } - } - - A.makeCompressed(); - - return A; -} - -DenseVector BSpline::Builder::getSamplePointValues() const -{ - DenseVector B = DenseVector::Zero(_data.getNumSamples()); - - int i = 0; - for (auto it = _data.cbegin(); it != _data.cend(); ++it, ++i) - B(i) = it->getY(); - - return B; -} - -/* -* Function for generating second order finite-difference matrix, which is used for penalizing the -* (approximate) second derivative in control point calculation for P-splines. -*/ -SparseMatrix BSpline::Builder::getSecondOrderFiniteDifferenceMatrix(const BSpline &bspline) const -{ - unsigned int numVariables = bspline.getNumVariables(); - - // Number of (total) basis functions - defines the number of columns in D - unsigned int numCols = bspline.getNumBasisFunctions(); - std::vector numBasisFunctions = bspline.getNumBasisFunctionsPerVariable(); - - // Number of basis functions (and coefficients) in each variable - std::vector dims; - for (unsigned int i = 0; i < numVariables; i++) - dims.push_back(numBasisFunctions.at(i)); - - std::reverse(dims.begin(), dims.end()); - - for (unsigned int i=0; i < numVariables; ++i) - if (numBasisFunctions.at(i) < 3) - throw Exception("BSpline::Builder::getSecondOrderDifferenceMatrix: Need at least three coefficients/basis function per variable."); - - // Number of rows in D and in each block - int numRows = 0; - std::vector< int > numBlkRows; - for (unsigned int i = 0; i < numVariables; i++) - { - int prod = 1; - for (unsigned int j = 0; j < numVariables; j++) - { - if (i == j) - prod *= (dims[j] - 2); - else - prod *= dims[j]; - } - numRows += prod; - numBlkRows.push_back(prod); - } - - // Resize and initialize D - SparseMatrix D(numRows, numCols); - D.reserve(DenseVector::Constant(numCols,2*numVariables)); // D has no more than two elems per col per dim - - int i = 0; // Row index - // Loop though each dimension (each dimension has its own block) - for (unsigned int d = 0; d < numVariables; d++) - { - // Calculate left and right products - int leftProd = 1; - int rightProd = 1; - for (unsigned int k = 0; k < d; k++) - { - leftProd *= dims[k]; - } - for (unsigned int k = d+1; k < numVariables; k++) - { - rightProd *= dims[k]; - } - - // Loop through subblocks on the block diagonal - for (int j = 0; j < rightProd; j++) - { - // Start column of current subblock - int blkBaseCol = j*leftProd*dims[d]; - // Block rows [I -2I I] of subblock - for (unsigned int l = 0; l < (dims[d] - 2); l++) - { - // Special case for first dimension - if (d == 0) - { - int k = j*leftProd*dims[d] + l; - D.insert(i,k) = 1; - k += leftProd; - D.insert(i,k) = -2; - k += leftProd; - D.insert(i,k) = 1; - i++; - } - else - { - // Loop for identity matrix - for (int n = 0; n < leftProd; n++) - { - int k = blkBaseCol + l*leftProd + n; - D.insert(i,k) = 1; - k += leftProd; - D.insert(i,k) = -2; - k += leftProd; - D.insert(i,k) = 1; - i++; - } - } - } - } - } - - D.makeCompressed(); - - return D; -} - -// Compute all knot vectors from sample data -std::vector > BSpline::Builder::computeKnotVectors() const -{ - if (_data.getNumVariables() != _degrees.size()) - throw Exception("BSpline::Builder::computeKnotVectors: Inconsistent sizes on input vectors."); - - std::vector> grid = _data.getTableX(); - - std::vector> knotVectors; - - for (unsigned int i = 0; i < _data.getNumVariables(); ++i) - { - // Compute knot vector - auto knotVec = computeKnotVector(grid.at(i), _degrees.at(i), _numBasisFunctions.at(i)); - - knotVectors.push_back(knotVec); - } - - return knotVectors; -} - -// Compute a single knot vector from sample grid and degree -std::vector BSpline::Builder::computeKnotVector(const std::vector &values, - unsigned int degree, - unsigned int numBasisFunctions) const -{ - switch (_knotSpacing) - { - case KnotSpacing::AS_SAMPLED: - return knotVectorMovingAverage(values, degree); - case KnotSpacing::EQUIDISTANT: - return knotVectorEquidistant(values, degree, numBasisFunctions); - case KnotSpacing::EXPERIMENTAL: - return knotVectorBuckets(values, degree); - default: - return knotVectorMovingAverage(values, degree); - } -} - -/* -* Automatic construction of (p+1)-regular knot vector -* using moving average. -* -* Requirement: -* Knot vector should be of size n+p+1. -* End knots are should be repeated p+1 times. -* -* Computed sizes: -* n+2*(p) = n + p + 1 + (p - 1) -* k = (p - 1) values must be removed from sample vector. -* w = k + 3 window size in moving average -* -* Algorithm: -* 1) compute n - k values using moving average with window size w -* 2) repeat first and last value p + 1 times -* -* The resulting knot vector has n - k + 2*p = n + p + 1 knots. -* -* NOTE: -* For equidistant samples, the resulting knot vector is identically to -* the free end conditions knot vector used in cubic interpolation. -* That is, samples (a,b,c,d,e,f) produces the knot vector (a,a,a,a,c,d,f,f,f,f) for p = 3. -* For p = 1, (a,b,c,d,e,f) becomes (a,a,b,c,d,e,f,f). -* -* TODO: -* Does not work well when number of knots is << number of samples! For such cases -* almost all knots will lie close to the left samples. Try a bucket approach, where the -* samples are added to buckets and the knots computed as the average of these. -*/ -std::vector BSpline::Builder::knotVectorMovingAverage(const std::vector &values, - unsigned int degree) const -{ - // Sort and remove duplicates - std::vector unique = extractUniqueSorted(values); - - // Compute sizes - unsigned int n = unique.size(); - unsigned int k = degree-1; // knots to remove - unsigned int w = k + 3; // Window size - - // The minimum number of samples from which a free knot vector can be created - if (n < degree+1) - { - std::ostringstream e; - e << "knotVectorMovingAverage: Only " << n - << " unique interpolation points are given. A minimum of degree+1 = " << degree+1 - << " unique points are required to build a B-spline basis of degree " << degree << "."; - throw Exception(e.str()); - } - - std::vector knots(n-k-2, 0); - - // Compute (n-k-2) interior knots using moving average - for (unsigned int i = 0; i < n-k-2; ++i) - { - double ma = 0; - for (unsigned int j = 0; j < w; ++j) - ma += unique.at(i+j); - - knots.at(i) = ma/w; - } - - // Repeat first knot p + 1 times (for interpolation of start point) - for (unsigned int i = 0; i < degree + 1; ++i) - knots.insert(knots.begin(), unique.front()); - - // Repeat last knot p + 1 times (for interpolation of end point) - for (unsigned int i = 0; i < degree + 1; ++i) - knots.insert(knots.end(), unique.back()); - - // Number of knots in a (p+1)-regular knot vector - //assert(knots.size() == uniqueX.size() + degree + 1); - - return knots; -} - -std::vector BSpline::Builder::knotVectorEquidistant(const std::vector &values, - unsigned int degree, - unsigned int numBasisFunctions = 0) const -{ - // Sort and remove duplicates - std::vector unique = extractUniqueSorted(values); - - // Compute sizes - unsigned int n = unique.size(); - if (numBasisFunctions > 0) - n = numBasisFunctions; - unsigned int k = degree-1; // knots to remove - - // The minimum number of samples from which a free knot vector can be created - if (n < degree+1) - { - std::ostringstream e; - e << "knotVectorMovingAverage: Only " << n - << " unique interpolation points are given. A minimum of degree+1 = " << degree+1 - << " unique points are required to build a B-spline basis of degree " << degree << "."; - throw Exception(e.str()); - } - - // Compute (n-k-2) equidistant interior knots - unsigned int numIntKnots = std::max(n-k-2, (unsigned int)0); - numIntKnots = std::min((unsigned int)10, numIntKnots); - std::vector knots = linspace(unique.front(), unique.back(), numIntKnots); - - // Repeat first knot p + 1 times (for interpolation of start point) - for (unsigned int i = 0; i < degree; ++i) - knots.insert(knots.begin(), unique.front()); - - // Repeat last knot p + 1 times (for interpolation of end point) - for (unsigned int i = 0; i < degree; ++i) - knots.insert(knots.end(), unique.back()); - - // Number of knots in a (p+1)-regular knot vector - //assert(knots.size() == uniqueX.size() + degree + 1); - - return knots; -} - -std::vector BSpline::Builder::knotVectorBuckets(const std::vector &values, unsigned int degree, unsigned int maxSegments) const -{ - // Sort and remove duplicates - std::vector unique = extractUniqueSorted(values); - - // The minimum number of samples from which a free knot vector can be created - if (unique.size() < degree+1) - { - std::ostringstream e; - e << "BSpline::Builder::knotVectorBuckets: Only " << unique.size() - << " unique sample points are given. A minimum of degree+1 = " << degree+1 - << " unique points are required to build a B-spline basis of degree " << degree << "."; - throw Exception(e.str()); - } - - // Num internal knots (0 <= ni <= unique.size() - degree - 1) - unsigned int ni = unique.size() - degree - 1; - - // Num segments - unsigned int ns = ni + degree + 1; - - // Limit number of segments - if (ns > maxSegments && maxSegments >= degree + 1) - { - ns = maxSegments; - ni = ns - degree - 1; - } - - // Num knots -// unsigned int nk = ns + degree + 1; - - // Check numbers - if (ni > unique.size() - degree - 1) - throw Exception("BSpline::Builder::knotVectorBuckets: Invalid number of internal knots!"); - - // Compute window sizes - unsigned int w = 0; - if (ni > 0) - w = (unsigned int)std::floor(unique.size()/ni); - - // Residual - unsigned int res = unique.size() - w*ni; - - // Create array with window sizes - std::vector windows(ni, w); - - // Add residual - for (unsigned int i = 0; i < res; ++i) - windows.at(i) += 1; - - // Compute internal knots - std::vector knots(ni, 0); - - // Compute (n-k-2) interior knots using moving average - unsigned int index = 0; - for (unsigned int i = 0; i < ni; ++i) - { - for (unsigned int j = 0; j < windows.at(i); ++j) - { - knots.at(i) += unique.at(index+j); - } - knots.at(i) /= windows.at(i); - index += windows.at(i); - } - - // Repeat first knot p + 1 times (for interpolation of start point) - for (unsigned int i = 0; i < degree + 1; ++i) - knots.insert(knots.begin(), unique.front()); - - // Repeat last knot p + 1 times (for interpolation of end point) - for (unsigned int i = 0; i < degree + 1; ++i) - knots.insert(knots.end(), unique.back()); - - return knots; -} - -std::vector BSpline::Builder::extractUniqueSorted(const std::vector &values) const -{ - // Sort and remove duplicates - std::vector unique(values); - std::sort(unique.begin(), unique.end()); - std::vector::iterator it = unique_copy(unique.begin(), unique.end(), unique.begin()); - unique.resize(distance(unique.begin(),it)); - return unique; -} - -} // namespace SPLINTER \ No newline at end of file diff --git a/splinter/bsplinebuilder.h b/splinter/bsplinebuilder.h deleted file mode 100644 index 7e56d325aa..0000000000 --- a/splinter/bsplinebuilder.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -#ifndef SPLINTER_BSPLINEBUILDER_H -#define SPLINTER_BSPLINEBUILDER_H - -#include "datatable.h" -#include "bspline.h" - -namespace SPLINTER -{ - -// B-spline smoothing -enum class BSpline::Smoothing -{ - NONE, // No smoothing - IDENTITY, // Regularization term alpha*c'*I*c is added to OLS objective - PSPLINE // Smoothing term alpha*Delta(c,2) is added to OLS objective -}; - -// B-spline knot spacing -/* - * To be added: - * AS_SAMPLED_NOT_CLAMPED // Place knots close to sample points. Without clamps. - * EQUIDISTANT_NOT_CLAMPED // Equidistant knots without clamps. - */ -enum class BSpline::KnotSpacing -{ - AS_SAMPLED, // Mimic spacing of sample points (moving average). With clamps (p+1 multiplicity of end knots). - EQUIDISTANT, // Equidistant knots. With clamps (p+1 multiplicity of end knots). - EXPERIMENTAL // Experimental knot spacing (for testing purposes). -}; - -// B-spline builder class -class SPLINTER_API BSpline::Builder -{ -public: - Builder(const DataTable &data); - - Builder& alpha(double alpha) - { - if (alpha < 0) - throw Exception("BSpline::Builder::alpha: alpha must be non-negative."); - - _alpha = alpha; - return *this; - } - - // Set build options - - Builder& degree(unsigned int degree) - { - _degrees = getBSplineDegrees(_data.getNumVariables(), degree); - return *this; - } - - Builder& degree(std::vector degrees) - { - if (degrees.size() != _data.getNumVariables()) - throw Exception("BSpline::Builder: Inconsistent length on degree vector."); - _degrees = degrees; - return *this; - } - - Builder& numBasisFunctions(unsigned int numBasisFunctions) - { - _numBasisFunctions = std::vector(_data.getNumVariables(), numBasisFunctions); - return *this; - } - - Builder& numBasisFunctions(std::vector numBasisFunctions) - { - if (numBasisFunctions.size() != _data.getNumVariables()) - throw Exception("BSpline::Builder: Inconsistent length on numBasisFunctions vector."); - _numBasisFunctions = numBasisFunctions; - return *this; - } - - Builder& knotSpacing(KnotSpacing knotSpacing) - { - _knotSpacing = knotSpacing; - return *this; - } - - Builder& smoothing(Smoothing smoothing) - { - _smoothing = smoothing; - return *this; - } - - // Build B-spline - BSpline build() const; - -private: - Builder(); - - std::vector getBSplineDegrees(unsigned int numVars, unsigned int degree) - { - if (degree > 5) - throw Exception("BSpline::Builder: Only degrees in range [0, 5] are supported."); - return std::vector(numVars, degree); - } - - // Control point computations - DenseVector computeCoefficients(const BSpline &bspline) const; - DenseVector computeBSplineCoefficients(const BSpline &bspline) const; - SparseMatrix computeBasisFunctionMatrix(const BSpline &bspline) const; - DenseVector getSamplePointValues() const; - // P-spline control point calculation - SparseMatrix getSecondOrderFiniteDifferenceMatrix(const BSpline &bspline) const; - - // Computing knots - std::vector> computeKnotVectors() const; - std::vector computeKnotVector(const std::vector &values, unsigned int degree, unsigned int numBasisFunctions) const; - std::vector knotVectorMovingAverage(const std::vector &values, unsigned int degree) const; - std::vector knotVectorEquidistant(const std::vector &values, unsigned int degree, unsigned int numBasisFunctions) const; - std::vector knotVectorBuckets(const std::vector &values, unsigned int degree, unsigned int maxSegments = 10) const; - - // Auxiliary - std::vector extractUniqueSorted(const std::vector &values) const; - - // Member variables - DataTable _data; - std::vector _degrees; - std::vector _numBasisFunctions; - KnotSpacing _knotSpacing; - Smoothing _smoothing; - double _alpha; -}; - -} // namespace SPLINTER - -#endif // SPLINTER_BSPLINEBUILDER_H diff --git a/splinter/datapoint.cpp b/splinter/datapoint.cpp deleted file mode 100644 index 8e2d5256ab..0000000000 --- a/splinter/datapoint.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -#include "datapoint.h" - -namespace SPLINTER -{ - -DataPoint::DataPoint() -{ -} - -DataPoint::DataPoint(double x, double y) -{ - setData(std::vector(1, x), y); -} - -DataPoint::DataPoint(std::vector x, double y) -{ - setData(x, y); -} - -DataPoint::DataPoint(DenseVector x, double y) -{ - std::vector newX; - - for (int i = 0; i < x.size(); i++) - { - newX.push_back(x(i)); - } - - setData(newX, y); -} - -void DataPoint::setData(const std::vector &x, double y) -{ - this->x = x; - this->y = y; -} - -bool DataPoint::operator<(const DataPoint &rhs) const -{ - if (this->getDimX() != rhs.getDimX()) - throw Exception("DataPoint::operator<: Cannot compare data points of different dimensions"); - - for (unsigned int i = 0; i < this->getDimX(); i++) - { - if (x.at(i) < rhs.getX().at(i)) - return true; - else if (x.at(i) > rhs.getX().at(i)) - return false; - } - - return false; -} - -/* -* Computes Euclidean distance ||x-y|| -*/ -double dist(const std::vector x, const std::vector y) -{ - if (x.size() != y.size()) - throw Exception("DataPoint::dist: Cannot measure distance between two points of different dimension"); - double sum = 0.0; - for (unsigned int i=0; i zeros(x.getDimX(), 0); - DataPoint origin(zeros, 0.0); - double x_dist = dist(x, origin); - double y_dist = dist(y, origin); - return (x_dist x, double y); - DataPoint(DenseVector x, double y); - - bool operator<(const DataPoint &rhs) const; // Returns false if the two are equal - - std::vector getX() const { return x; } - double getY() const { return y; } - unsigned int getDimX() const { return (unsigned int)x.size(); } - -private: - DataPoint(); - - std::vector x; - double y; - void setData(const std::vector &x, double y); - - friend class Serializer; -}; - -// Measure distance between two points -double dist(const std::vector x, const std::vector y); -double dist(const DataPoint x, const DataPoint y); -bool dist_sort(const DataPoint x, const DataPoint y); - -} // namespace SPLINTER - -#endif // SPLINTER_DATAPOINT_H diff --git a/splinter/datatable.cpp b/splinter/datatable.cpp deleted file mode 100644 index 24faafca02..0000000000 --- a/splinter/datatable.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -#include -#include -#include -#include -#include -#include -#include "datatable.h" -#include "serializer.h" - -namespace SPLINTER -{ - -DataTable::DataTable() - : DataTable(false, false) -{ -} - -DataTable::DataTable(bool allowDuplicates) - : DataTable(allowDuplicates, false) -{ -} - -DataTable::DataTable(bool allowDuplicates, bool allowIncompleteGrid) - : allowDuplicates(allowDuplicates), - allowIncompleteGrid(allowIncompleteGrid), - numDuplicates(0), - numVariables(0) -{ -} - -DataTable::DataTable(const char *fileName) - : DataTable(std::string(fileName)) -{ -} - -DataTable::DataTable(const std::string &fileName) -{ - load(fileName); -} - -void DataTable::addSample(double x, double y) -{ - addSample(DataPoint(x, y)); -} - -void DataTable::addSample(std::vector x, double y) -{ - addSample(DataPoint(x, y)); -} - -void DataTable::addSample(DenseVector x, double y) -{ - addSample(DataPoint(x, y)); -} - -void DataTable::addSample(const DataPoint &sample) -{ - if (getNumSamples() == 0) - { - numVariables = sample.getDimX(); - initDataStructures(); - } - - if(sample.getDimX() != numVariables) { - throw Exception("Datatable::addSample: Dimension of new sample is inconsistent with previous samples!"); - } - - // Check if the sample has been added already - if (samples.count(sample) > 0) - { - if (!allowDuplicates) - { -#ifndef NDEBUG - std::cout << "Discarding duplicate sample because allowDuplicates is false!" << std::endl; - std::cout << "Initialise with DataTable(true) to set it to true." << std::endl; -#endif // NDEBUG - - return; - } - - numDuplicates++; - } - - samples.insert(sample); - - recordGridPoint(sample); -} - -void DataTable::addSample(std::initializer_list samples) -{ - for (auto& sample : samples) - { - addSample(sample); - } -} - -void DataTable::recordGridPoint(const DataPoint &sample) -{ - for (unsigned int i = 0; i < getNumVariables(); i++) - { - grid.at(i).insert(sample.getX().at(i)); - } -} - -unsigned int DataTable::getNumSamplesRequired() const -{ - unsigned long samplesRequired = 1; - unsigned int i = 0; - for (auto &variable : grid) - { - samplesRequired *= (unsigned long) variable.size(); - i++; - } - - return (i > 0 ? samplesRequired : (unsigned long) 0); -} - -bool DataTable::isGridComplete() const -{ - return samples.size() > 0 && samples.size() - numDuplicates == getNumSamplesRequired(); -} - -void DataTable::initDataStructures() -{ - for (unsigned int i = 0; i < getNumVariables(); i++) - { - grid.push_back(std::set()); - } -} - -void DataTable::gridCompleteGuard() const -{ - if (!(isGridComplete() || allowIncompleteGrid)) - { - throw Exception("DataTable::gridCompleteGuard: The grid is not complete yet!"); - } -} - -void DataTable::save(const std::string &fileName) const -{ - Serializer s; - s.serialize(*this); - s.saveToFile(fileName); -} - -void DataTable::load(const std::string &fileName) -{ - Serializer s(fileName); - s.deserialize(*this); -} - -/* - * Getters for iterators - */ -std::multiset::const_iterator DataTable::cbegin() const -{ - return samples.cbegin(); -} - -std::multiset::const_iterator DataTable::cend() const -{ - return samples.cend(); -} - -/* - * Get table of samples x-values, - * i.e. table[i][j] is the value of variable i at sample j - */ -std::vector< std::vector > DataTable::getTableX() const -{ - gridCompleteGuard(); - - // Initialize table - std::vector> table; - for (unsigned int i = 0; i < numVariables; i++) - { - std::vector xi(getNumSamples(), 0.0); - table.push_back(xi); - } - - // Fill table with values - int i = 0; - for (auto &sample : samples) - { - std::vector x = sample.getX(); - - for (unsigned int j = 0; j < numVariables; j++) - { - table.at(j).at(i) = x.at(j); - } - i++; - } - - return table; -} - -// Get vector of y-values -std::vector DataTable::getVectorY() const -{ - std::vector y; - for (std::multiset::const_iterator it = cbegin(); it != cend(); ++it) - { - y.push_back(it->getY()); - } - return y; -} - -DataTable operator+(const DataTable &lhs, const DataTable &rhs) -{ - if(lhs.getNumVariables() != rhs.getNumVariables()) { - throw Exception("operator+(DataTable, DataTable): trying to add two DataTable's of different dimensions!"); - } - - DataTable result; - for(auto it = lhs.cbegin(); it != lhs.cend(); it++) { - result.addSample(*it); - } - for(auto it = rhs.cbegin(); it != rhs.cend(); it++) { - result.addSample(*it); - } - - return result; -} - -DataTable operator-(const DataTable &lhs, const DataTable &rhs) -{ - if(lhs.getNumVariables() != rhs.getNumVariables()) { - throw Exception("operator-(DataTable, DataTable): trying to subtract two DataTable's of different dimensions!"); - } - - DataTable result; - auto rhsSamples = rhs.getSamples(); - // Add all samples from lhs that are not in rhs - for(auto it = lhs.cbegin(); it != lhs.cend(); it++) { - if(rhsSamples.count(*it) == 0) { - result.addSample(*it); - } - } - - return result; -} - -} // namespace SPLINTER diff --git a/splinter/datatable.h b/splinter/datatable.h deleted file mode 100644 index d8255327c5..0000000000 --- a/splinter/datatable.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -#ifndef SPLINTER_DATATABLE_H -#define SPLINTER_DATATABLE_H - -#include -#include "datapoint.h" - -#include - -namespace SPLINTER -{ - -/* - * DataTable is a class for storing multidimensional data samples (x,y). - * The samples are stored in a continuously sorted table. - */ -class SPLINTER_API DataTable -{ -public: - DataTable(); - DataTable(bool allowDuplicates); - DataTable(bool allowDuplicates, bool allowIncompleteGrid); - DataTable(const char *fileName); - DataTable(const std::string &fileName); // Load DataTable from file - - /* - * Functions for adding a sample (x,y) - */ - void addSample(const DataPoint &sample); - void addSample(double x, double y); - void addSample(std::vector x, double y); - void addSample(DenseVector x, double y); - void addSample(std::initializer_list samples); - - /* - * Getters - */ - std::multiset::const_iterator cbegin() const; - std::multiset::const_iterator cend() const; - - unsigned int getNumVariables() const {return numVariables;} - unsigned int getNumSamples() const {return (unsigned int)samples.size();} - const std::multiset& getSamples() const {return samples;} - - std::vector> getGrid() const { return grid; } - std::vector< std::vector > getTableX() const; - std::vector getVectorY() const; - - bool isGridComplete() const; - - void save(const std::string &fileName) const; - - void clear() { samples.clear(); grid.clear(); } - -private: - bool allowDuplicates; - bool allowIncompleteGrid; - unsigned int numDuplicates; - unsigned int numVariables; - - std::multiset samples; - std::vector< std::set > grid; - - void initDataStructures(); // Initialise grid to be a std::vector of xDim std::sets - unsigned int getNumSamplesRequired() const; - - void recordGridPoint(const DataPoint &sample); - - // Used by functions that require the grid to be complete before they start their operation - // This function prints a message and exits the program if the grid is not complete. - void gridCompleteGuard() const; - - void load(const std::string &fileName); - - friend class Serializer; - friend bool operator==(const DataTable &lhs, const DataTable &rhs); -}; - -DataTable operator+(const DataTable &lhs, const DataTable &rhs); -DataTable operator-(const DataTable &lhs, const DataTable &rhs); - -} // namespace SPLINTER - -#endif // SPLINTER_DATATABLE_H diff --git a/splinter/function.cpp b/splinter/function.cpp deleted file mode 100644 index 6db20a0fcd..0000000000 --- a/splinter/function.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -#include "function.h" -#include "utilities.h" - -namespace SPLINTER -{ - -double Function::eval(const std::vector &x) const -{ - auto denseX = vectorToDenseVector(x); - - return eval(denseX); -} - -std::vector Function::evalJacobian(const std::vector &x) const -{ - auto denseX = vectorToDenseVector(x); - - return denseVectorToVector(evalJacobian(denseX)); -} - -std::vector> Function::evalHessian(const std::vector &x) const -{ - auto denseX = vectorToDenseVector(x); - - return denseMatrixToVectorVector(secondOrderCentralDifference(denseX)); -} - -std::vector Function::centralDifference(const std::vector &x) const -{ - auto denseX = vectorToDenseVector(x); - - auto dx = centralDifference(denseX); - - return denseVectorToVector(dx); -} - -std::vector> Function::secondOrderCentralDifference(const std::vector &x) const -{ - auto denseX = vectorToDenseVector(x); - - DenseMatrix ddx = secondOrderCentralDifference(denseX); - - return denseMatrixToVectorVector(ddx); -} - -DenseMatrix Function::evalJacobian(DenseVector x) const -{ - return centralDifference(x); -} - -DenseMatrix Function::evalHessian(DenseVector x) const -{ - auto vec = denseVectorToVector(x); - - auto hessian = evalHessian(vec); - - return vectorVectorToDenseMatrix(hessian); -} - -DenseMatrix Function::centralDifference(DenseVector x) const -{ - DenseMatrix dx(1, x.size()); - - double h = 1e-6; // perturbation step size - double hForward = 0.5*h; - double hBackward = 0.5*h; - - for (unsigned int i = 0; i < getNumVariables(); ++i) - { - DenseVector xForward(x); - xForward(i) = xForward(i) + hForward; - - DenseVector xBackward(x); - xBackward(i) = xBackward(i) - hBackward; - - double yForward = eval(xForward); - double yBackward = eval(xBackward); - - dx(i) = (yForward - yBackward)/(hBackward + hForward); - } - - return dx; -} - -DenseMatrix Function::secondOrderCentralDifference(DenseVector x) const -{ - DenseMatrix ddx(getNumVariables(), getNumVariables()); - - double h = 1e-6; // perturbation step size - double hForward = 0.5*h; - double hBackward = 0.5*h; - - for (size_t i = 0; i < getNumVariables(); ++i) - { - for (size_t j = 0; j < getNumVariables(); ++j) - { - DenseVector x0(x); - DenseVector x1(x); - DenseVector x2(x); - DenseVector x3(x); - - x0(i) = x0(i) + hForward; - x0(j) = x0(j) + hForward; - - x1(i) = x1(i) - hBackward; - x1(j) = x1(j) + hForward; - - x2(i) = x2(i) + hForward; - x2(j) = x2(j) - hBackward; - - x3(i) = x3(i) - hBackward; - x3(j) = x3(j) - hBackward; - - ddx(i, j) = (eval(x0) - eval(x1) - eval(x2) + eval(x3)) / (h * h); - } - } - - return ddx; -} - -} // namespace SPLINTER \ No newline at end of file diff --git a/splinter/function.h b/splinter/function.h deleted file mode 100644 index 0a321671af..0000000000 --- a/splinter/function.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -#ifndef SPLINTER_FUNCTION_H -#define SPLINTER_FUNCTION_H - -#include "definitions.h" -#include "saveable.h" - -namespace SPLINTER -{ - -/* - * Interface for functions - * All functions working with standard C++11 types are defined in terms of their Eigen counterparts. - * Default implementations of jacobian and hessian evaluation is using central difference. - * TODO: Remove current requirement that all functions must implement save and load! - */ -class SPLINTER_API Function : public Saveable -{ -public: - Function() - : Function(1) {} - - Function(unsigned int numVariables) - : numVariables(numVariables) {} - - virtual ~Function() {} - - /** - * Returns the function value at x - */ - virtual double eval(DenseVector x) const = 0; - - /** - * Returns the function value at x - */ - double eval(const std::vector &x) const; - - /** - * Returns the (1 x numVariables) Jacobian evaluated at x - */ - virtual DenseMatrix evalJacobian(DenseVector x) const; - - /** - * Returns the (1 x numVariables) Jacobian evaluated at x - */ - std::vector evalJacobian(const std::vector &x) const; - - /** - * Returns the (numVariables x numVariables) Hessian evaluated at x - */ - virtual DenseMatrix evalHessian(DenseVector x) const; - - /** - * Returns the (numVariables x numVariables) Hessian evaluated at x - */ - std::vector> evalHessian(const std::vector &x) const; - - /** - * Get the dimension - */ - inline unsigned int getNumVariables() const - { - return numVariables; - } - - /** - * Check input - */ - void checkInput(DenseVector x) const { - if (x.size() != (int)numVariables) - throw Exception("Function::checkInput: Wrong dimension on evaluation point x."); - } - - /** - * Returns the central difference at x - * Vector of numVariables length - */ - std::vector centralDifference(const std::vector &x) const; - DenseMatrix centralDifference(DenseVector x) const; - - std::vector> secondOrderCentralDifference(const std::vector &x) const; - DenseMatrix secondOrderCentralDifference(DenseVector x) const; - - /** - * Description of function. - */ - virtual std::string getDescription() const - { - return ""; - } - -protected: - unsigned int numVariables; // Dimension of domain (size of x) - - friend class Serializer; -}; - -} // namespace SPLINTER - -#endif // SPLINTER_FUNCTION_H \ No newline at end of file diff --git a/splinter/include/bspline.h b/splinter/include/bspline.h new file mode 100644 index 0000000000..92f83ba1ff --- /dev/null +++ b/splinter/include/bspline.h @@ -0,0 +1,175 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#ifndef SPLINTER_BSPLINE_H +#define SPLINTER_BSPLINE_H + +#include "function.h" +#include "bspline_basis.h" +#include "data_table.h" +#include "json_parser.h" + + +namespace SPLINTER +{ + +/** + * Class that implements the multivariate tensor product B-spline + */ +class SPLINTER_API BSpline : public Function +{ +public: + + // B-spline smoothing + enum class Smoothing { + NONE, // No smoothing + IDENTITY, // Regularization term alpha*c'*I*c is added to OLS objective + PSPLINE // Second-order difference penalty alpha*Delta(c,2) is added to OLS objective + }; + + /** + * Construct B-spline from basis degree and knot vectors. Default output dimension is 1. + */ + BSpline(const std::vector °rees, const std::vector> &knot_vectors, + unsigned int dim_y = 1); + + /** + * Construct B-spline from basis degree, knot vectors and control points. + */ + BSpline(const std::vector °rees, const std::vector> &knot_vectors, + const std::vector> &control_points); + + virtual BSpline* clone() const { return new BSpline(*this); } + + /** + * Evaluation of B-spline + */ + + // Avoid name hiding + using Function::eval; + using Function::eval_jacobian; + + // Evaluate the B-spline at x. Returns vector of size (dim_y). + std::vector eval(const std::vector &x) const override; + DenseVector eval(const DenseVector &x) const override; + + // Evaluate the Jacobian at x. Returns matrix of size (dim_y, dim_x). + DenseMatrix eval_jacobian(const DenseVector &x) const override; + + // Evaluate the Hessian at x. Returns tensor of size (dim_y, dim_x, dim_x). + std::vector>> eval_hessian(const std::vector &x) const; + + // Evaluate B-spline basis functions at x. Returns vector of size (num_basis_functions). + SparseVector eval_basis(const DenseVector &x) const; + + // Evaluate Jacobian of B-spline basis functions at x. Returns vector of size (num_basis_functions, num_x). + SparseMatrix eval_basis_jacobian(const DenseVector &x) const; + + /** + * Getters + */ + DenseMatrix get_control_points() const + { + return control_points; + } + + unsigned int get_num_control_points() const + { + return (unsigned int) control_points.rows(); + } + + std::vector get_num_basis_functions_per_variable() const; + + unsigned int get_num_basis_functions() const + { + return basis.get_num_basis_functions(); + } + + unsigned int get_num_supported() const + { + return basis.num_supported(); + } + + DenseMatrix get_knot_averages() const { + return compute_knot_averages(); + }; + std::vector< std::vector> get_knot_vectors() const; + std::vector get_basis_degrees() const; + std::vector get_domain_upper_bound() const; + std::vector get_domain_lower_bound() const; + + /** + * Setters + */ + void set_control_points(const DenseMatrix &new_control_points); + + /** + * Manipulations to B-spline + */ + + // Linear transformation of control points (B-spline has affine invariance) + void linear_transform(const SparseMatrix &A); + + // Fit B-spline to sample data + BSpline& fit(const DataTable &data, Smoothing smoothing = Smoothing::NONE, double alpha = .1, + std::vector weights = std::vector()); + + // Reduce support of B-spline + void reduce_support(const std::vector &lb, const std::vector &ub, + bool regularize_knot_vectors = true); + + // Perform global knot refinement (all knots in one shabang) + void global_knot_refinement(); + + // Perform a local knot refinement at x + void local_knot_refinement(const DenseVector &x); + + // Decompose B-spline to Bezier form + void decompose_to_bezier(); + + // Insert a knot until desired knot multiplicity is obtained + void insert_knots(double tau, unsigned int dim, unsigned int multiplicity = 1); + + /** + * Save and load + */ + void to_json(const std::string &filename) const; + + static BSpline from_json(const std::string &filename); + + /** + * Helper functions + */ + void check_control_points() const; + std::string get_description() const override; + +protected: + // B-spline basis functions (multivariate) + BSplineBasis basis; + + // B-spline control points of size (num_basis_functions, dim_y). Each row is a control point. + DenseMatrix control_points; + + // Control point computations + DenseMatrix compute_knot_averages() const; + +private: + // Domain reduction + void regularize_knot_vectors(const std::vector &lb, const std::vector &ub); + bool remove_unsupported_basis_functions(const std::vector &lb, const std::vector &ub); + + // Helper functions + bool is_supported(const DenseVector &x) const; + + friend bool operator==(const BSpline &lhs, const BSpline &rhs); +}; + +} // namespace SPLINTER + +#endif // SPLINTER_BSPLINE_H diff --git a/splinter/include/bspline_basis.h b/splinter/include/bspline_basis.h new file mode 100644 index 0000000000..16b8da01eb --- /dev/null +++ b/splinter/include/bspline_basis.h @@ -0,0 +1,73 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#ifndef SPLINTER_BSPLINE_BASIS_H +#define SPLINTER_BSPLINE_BASIS_H + +#include "definitions.h" +#include "bspline_basis_1d.h" + + +namespace SPLINTER +{ + +class BSplineBasis +{ +public: + // Constructor + BSplineBasis(std::vector degrees, const std::vector> &knot_vectors); + + // Evaluation + SparseVector eval(const DenseVector &x) const; + DenseMatrix eval_basis_jacobian_old(const DenseVector &x) const; // Deprecated + SparseMatrix eval_basis_jacobian(const DenseVector &x) const; + SparseMatrix eval_basis_jacobian2(const DenseVector &x) const; // A bit slower than evaBasisJacobianOld() + SparseMatrix eval_basis_hessian(const DenseVector &x) const; + + // Knot vector manipulation + SparseMatrix refine_knots(); + SparseMatrix refine_knots_locally(const DenseVector &x); + SparseMatrix decompose_to_bezier(); + SparseMatrix insert_knots(double tau, unsigned int dim, unsigned int multiplicity = 1); + + // Getters + BSplineBasis1D get_single_basis(unsigned int dim); + std::vector> get_knot_vectors() const; + std::vector get_knot_vector(int dim) const; + + std::vector get_basis_degrees() const; + unsigned int get_basis_degree(unsigned int dim) const; + unsigned int get_num_basis_functions() const; + unsigned int get_num_basis_functions(unsigned int dim) const; + std::vector get_num_basis_functions_target() const; + + unsigned int get_knot_multiplicity(unsigned int dim, double tau) const; + + /* + * Returns the maximum number of supported basis functions at any point in the B-spline domain + */ + unsigned int num_supported() const; + + bool inside_support(const DenseVector &x) const; + std::vector get_support_lower_bound() const; + std::vector get_support_upper_bound() const; + + // Support related + SparseMatrix reduce_support(const std::vector &lb, const std::vector &ub); + +private: + std::vector bases; + unsigned int num_variables; + + friend bool operator==(const BSplineBasis &lhs, const BSplineBasis &rhs); +}; + +} // namespace SPLINTER + +#endif // SPLINTER_BSPLINE_BASIS_H diff --git a/splinter/include/bspline_basis_1d.h b/splinter/include/bspline_basis_1d.h new file mode 100644 index 0000000000..98430ff08a --- /dev/null +++ b/splinter/include/bspline_basis_1d.h @@ -0,0 +1,101 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#ifndef SPLINTER_BSPLINE_BASIS_1D_H +#define SPLINTER_BSPLINE_BASIS_1D_H + +#include "definitions.h" +#include "knot_vector.h" + +namespace SPLINTER +{ + +class BSplineBasis1D +{ +public: + BSplineBasis1D(unsigned int degree, const std::vector &knots); + + /** + * Evaluation of basis functions + */ + SparseVector eval(double x) const; + SparseVector eval_derivative(double x, unsigned int r) const; + SparseVector eval_first_derivative(double x) const; // TODO: Deprecated + + /** + * Knot vector related + */ + SparseMatrix refine_knots(); + SparseMatrix refine_knots_locally(double x); + SparseMatrix decompose_to_bezier(); + SparseMatrix insert_knots(double tau, unsigned int multiplicity = 1); + // bool insert_knots(SparseMatrix &A, std::vector> newKnots); // Add knots at several locations + + unsigned int knot_multiplicity(double tau) const { + // Return the number of repetitions of tau in the knot vector + return knots.multiplicity(tau); + } + + /** + * Support related + */ + double support_hack(double x) const; + bool is_supported(double x) const { + return knots.is_supported(x); + } + SparseMatrix reduce_support(double lb, double ub); + + /** + * Getters + */ + std::vector get_knot_vector() const { return knots.get_values(); } + unsigned int get_basis_degree() const { return degree; } + unsigned int get_num_basis_functions() const; + unsigned int get_num_basis_functions_target() const; + + /** + * Index getters + */ + std::vector index_supported_basis_functions(double x) const; + unsigned int index_longest_interval(const std::vector &vec) const; + + /** + * Setters + */ + void set_num_basis_functions_target(unsigned int target) + { + target_num_basis_functions = std::max(degree+1, target); + } + +private: + unsigned int degree; + KnotVector knots; + unsigned int target_num_basis_functions; + + // DeBoorCox algorithm for evaluating basis functions + double de_boor_cox(double x, unsigned int i, unsigned int k) const; + double de_boor_cox_coeff(double x, double x_min, double x_max) const; + + // Builds basis matrix for alternative evaluation of basis functions + SparseMatrix build_basis_matrix(double x, unsigned int u, unsigned int k, bool diff = false) const; + + /** + * Builds knot insertion matrix + * Implements Oslo Algorithm 1 from Lyche and Moerken (2011). Spline methods draft. + */ + SparseMatrix build_knot_insertion_matrix(const std::vector &refined_knots) const; + + // Operators + friend bool operator==(const BSplineBasis1D &lhs, const BSplineBasis1D &rhs); + friend bool operator!=(const BSplineBasis1D &lhs, const BSplineBasis1D &rhs); +}; + +} // namespace SPLINTER + +#endif // SPLINTER_BSPLINE_BASIS_1D_H diff --git a/splinter/include/bspline_builders.h b/splinter/include/bspline_builders.h new file mode 100644 index 0000000000..3ac32cc729 --- /dev/null +++ b/splinter/include/bspline_builders.h @@ -0,0 +1,63 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#ifndef SPLINTER_BSPLINE_BUILDER_H +#define SPLINTER_BSPLINE_BUILDER_H + +#include +#include +#include + +namespace SPLINTER +{ + +/** + * Convenience functions for B-spline fitting + */ + + +/** + * Create a B-spline that interpolates the sample points. + * @param data A table of sample points on a regular grid. + * @param degree The degree of the B-spline basis functions. Default degree is 3 (cubic). + * @return A B-spline that interpolates the sample points. + */ +BSpline bspline_interpolator(const DataTable &data, unsigned int degree = 3); + + +/** + * Create a B-spline that smooths the sample points using regularization (weight decay). + * @param data A table of sample points on a regular grid. + * @param degree The degree of the B-spline basis functions. Default degree is 3 (cubic). + * @param smoothing Type of regularization to use - see BSpline::Smoothing. Default is smoothing is BSpline::PSLINE. + * @param alpha Smoothing/regularization factor. + * @param weights Sample weights. + * @return A B-spline that smooths the sample points. + */ +BSpline bspline_smoother(const DataTable &data, unsigned int degree = 3, + BSpline::Smoothing smoothing = BSpline::Smoothing::PSPLINE, double alpha = 0.1, + std::vector weights = std::vector()); + + +/** + * Create a unfitted (zero-valued) B-spline. This builder gives the user more control and allows for construction of + * B-splines with non-default knot vectors and different degrees for the univariate basis functions. + * @param data A table of sample points on a regular grid. + * @param degree The degrees of the B-spline basis functions. + * @param knot_spacing The knot spacing method used to build knot vectors. + * @param num_basis_functions The desired number of basis functions in each univariate basis (must be at least degree + 1). + * @return A B-spline that smooths the sample points. + */ +BSpline bspline_unfitted(const DataTable &data, const std::vector °rees, KnotSpacing knot_spacing, + const std::vector &num_basis_functions); + + +} // namespace SPLINTER + +#endif // SPLINTER_BSPLINE_BUILDER_H diff --git a/splinter/include/bspline_utils.h b/splinter/include/bspline_utils.h new file mode 100644 index 0000000000..98ec6ac715 --- /dev/null +++ b/splinter/include/bspline_utils.h @@ -0,0 +1,37 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#ifndef SPLINTER_BSPLINE_UTILS_H +#define SPLINTER_BSPLINE_UTILS_H + +#include +#include + +namespace SPLINTER +{ + +// Control point computations +DenseMatrix compute_control_points(const BSpline &bspline, const DataTable &data, BSpline::Smoothing smoothing, + double alpha, std::vector weights); + +// Matrix of basis functions evaluated at samples +SparseMatrix compute_basis_function_matrix(const BSpline &bspline, const DataTable &data); + +// Stack samples in DenseMatrix +DenseMatrix stack_sample_values(const DataTable &data); + +// P-spline control point calculation +SparseMatrix compute_second_order_finite_difference_matrix(const BSpline &bspline); + +// Compute weights matrix from weight vector +SparseMatrix compute_weight_matrix(std::vector weights); + +} // namespace SPLINTER + +#endif // SPLINTER_BSPLINE_UTILS_H diff --git a/splinter/include/cinterface/cinterface.h b/splinter/include/cinterface/cinterface.h new file mode 100644 index 0000000000..d7230e22e0 --- /dev/null +++ b/splinter/include/cinterface/cinterface.h @@ -0,0 +1,399 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#ifndef SPLINTER_CINTERFACE_H +#define SPLINTER_CINTERFACE_H + + +#ifndef SPLINTER_API +# ifdef _MSC_VER +# define SPLINTER_API __declspec(dllexport) +# else +# define SPLINTER_API +# endif +#endif + +// Pointer to C++ objects, passed into the C interface then cast to the correct type. +typedef void *splinter_obj_ptr; + + +#ifdef __cplusplus + extern "C" + { +#endif +/** + * Check if the last library call resulted in an error. + * Will reset upon call, so two consecutive calls to this function may not return the same value. + * + * @return 1 if error, 0 else. + */ +SPLINTER_API int splinter_get_error(); + +/** + * Get a string describing the error. + * + * @return Error string. + */ +SPLINTER_API const char *splinter_get_error_string(); + + + + + +/** + * Initialize a new DataTable. + * + * @return Pointer to the created DataTable. + */ +SPLINTER_API splinter_obj_ptr splinter_datatable_init(); + +/** + * Add samples that are stored in row major order to the datatable. + * + * If x0 = [x0_0, x0_1, x0_2], x1 = [x1_0, x1_1, x1_2] are two inputs with + * y0 = [y0_0, y0_1], y1 = [y1_0, y1_1], as the corresponding outputs, then + * + * xs = [x0_0, x0_1, x0_2, x1_0, x1_1, x1_2] + * x_dim = 3 + * ys = [y0_0, y0_1, y1_0, y1_1] + * y_dim = 2 + * n_samples = 2 + * + * @param datatable_ptr Pointer to the datatable. + * @param xs Pointer to the start of the inputs. + * @param x_dim The dimension of each input. + * @param ys Pointer to the start of the outputs. + * @param y_dim The dimension of each output. + * @param n_samples Number of samples to add (= xs/x_dim = ys/y_dim). + */ +SPLINTER_API void splinter_datatable_add_samples_row_major(splinter_obj_ptr datatable_ptr, + double *xs, int x_dim, + double *ys, int y_dim, + int n_samples); + +/** + * Add samples that are stored in column major order to the datatable. + * + * @param datatable_ptr Pointer to the datatable. + * @param x Pointer to the start of the samples. + * @param n_samples Number of samples to add. + * @param x_dim The dimension of each point (that is, the sample size - 1). + */ +SPLINTER_API void splinter_datatable_add_samples_col_major(splinter_obj_ptr datatable_ptr, double *x, int n_samples, int x_dim); + +/** + * Get the dimension of the domain of the samples in the datatable. + * + * @param datatable_ptr Pointer to the datatable. + * @return The dimension of the domain of the samples in the datatable. + */ +SPLINTER_API int splinter_datatable_get_dim_x(splinter_obj_ptr datatable_ptr); + +/** + * Get the dimension of the codomain of the samples in the datatable. + * + * @param datatable_ptr Pointer to the datatable. + * @return The dimension of the codomain of the samples in the datatable. + */ +SPLINTER_API int splinter_datatable_get_dim_y(splinter_obj_ptr datatable_ptr); + +/** + * Get the number of samples stored in the datatable. + * + * @param datatable_ptr Pointer to the datatable. + * @return The number of samples in the datatable. + */ +SPLINTER_API int splinter_datatable_get_num_samples(splinter_obj_ptr datatable_ptr); + +/** + * Save a DataTable to json file. + * + * @param datatable_ptr Pointer to the DataTable + * @param filename File to save the DataTable to (will be overwritten!) + */ +SPLINTER_API void splinter_datatable_to_json(splinter_obj_ptr datatable_ptr, const char *filename); + +/** + * Load a DataTable from json file. + * + * @param datatable_ptr Pointer to the DataTable + * @param filename File to save the DataTable to (will be overwritten!) + */ +SPLINTER_API splinter_obj_ptr splinter_datatable_from_json(const char *filename); + +/** + * Free the memory of a datatable. + * + * @param datatable_ptr Pointer to the datatable. + */ +SPLINTER_API void splinter_datatable_delete(splinter_obj_ptr datatable_ptr); + + + + +/** + * Construct a BSpline that interpolates the sample points. + * + * @param datatable_ptr The datatable with sample points. + * @param degree The degree of the B-spline basis functions. + * @return Pointer to the created BSpline. + */ +SPLINTER_API splinter_obj_ptr splinter_bspline_interpolator(splinter_obj_ptr datatable_ptr, int degree); + +/** + * Construct a BSpline that smooths the sample points using regularization (weight decay). + * + * @param datatable_ptr The datatable with sample points. + * @param degree The degree of the B-spline basis functions. + * @param alpha Smoothing/regularization factor. + * @return Pointer to the created BSpline. + */ +SPLINTER_API splinter_obj_ptr splinter_bspline_smoother(splinter_obj_ptr datatable_ptr, int degree, int smoothing, + double alpha, double *weights, unsigned int num_weights); + +/** + * Construct an unfitted (zero-valued) BSpline. + * + * @param datatable_ptr The datatable with sample points. + * @param degree The degree of the B-spline basis functions + * @param alpha Smoothing/regularization factor + * @return Pointer to the created BSpline. + */ +SPLINTER_API splinter_obj_ptr splinter_bspline_unfitted(splinter_obj_ptr datatable_ptr, unsigned int *degrees, + unsigned int num_degrees, int knot_spacing, + unsigned int *num_basis_functions, + unsigned int num_num_basis_functions); + + + +/** + * Construct a BSpline from parameters: coefficients, knot vectors and degrees. + * + * @param dim_x Number of inputs (variables) + * @param dim_y Number of outputs + * @param degrees B-spline degrees + * @param knot_vectors B-spline knot vectors + * @param num_knots_per_vector Number of knots per knot vector + * @param control_points B-spline control points + * @param num_control_points Number of coefficients + * @return Pointer to the created BSpline. + */ +SPLINTER_API splinter_obj_ptr splinter_bspline_from_param(unsigned int dim_x, unsigned int dim_y, unsigned int *degrees, + double *knot_vectors, unsigned int *num_knots_per_vector, + double *control_points, unsigned int num_control_points); + + +/** + * Construct a BSpline from parameters: knot vectors and degrees. Control points are set to zero. + * + * @param dim_x Number of inputs (variables) + * @param dim_y Number of outputs + * @param degrees B-spline degrees + * @param knot_vectors B-spline knot vectors + * @param num_knots_per_vector Number of knots per knot vector + * @return Pointer to the created BSpline. + */ +SPLINTER_API splinter_obj_ptr splinter_bspline_from_param_zero(unsigned int dim_x, unsigned int dim_y, + unsigned int *degrees, double *knot_vectors, + unsigned int *num_knots_per_vector); + +/** + * Get the sizes of the knot vectors that are returned by splinter_bspline_get_knot_vectors + * + * @param bspline_ptr Pointer to the BSpline + * @return Array of splinter_bspline_get_num_variables length + */ +SPLINTER_API int *splinter_bspline_get_knot_vector_sizes(splinter_obj_ptr bspline_ptr); + +/** + * Get the knot vectors of the BSpline + * Two-dimensional matrix where the rows are the knot vectors + * There are splinter_bspline_get_num_variables knot vectors + * The sizes of the knot vectors are given by splinter_bspline_get_knot_vector_sizes + * + * @param bspline_ptr Pointer to the BSpline + * @return Row major array of size stated above + */ +SPLINTER_API double *splinter_bspline_get_knot_vectors(splinter_obj_ptr bspline_ptr); + +/** + * Get the number of coefficients of the BSpline + * + * @param bspline_ptr Pointer to the BSpline + */ +SPLINTER_API int splinter_bspline_get_num_control_points(splinter_obj_ptr bspline_ptr); + +/** + * Get the control points of the BSpline + * Returns a two-dimensional matrix with + * splinter_bspline_get_num_control_points rows + * and splinter_bspline_get_num_outputs columns + * + * @param bspline_ptr Pointer to the BSpline + * @return Row major flattened array of the control points + */ +SPLINTER_API double *splinter_bspline_get_control_points(splinter_obj_ptr bspline_ptr); + +/** + * Get the knot averages of the BSpline + * Returns a two-dimensional matrix with + * splinter_bspline_get_num_control_points rows + * and splinter_bspline_get_num_variables columns + * + * @param bspline_ptr Pointer to the BSpline + * @return Row major flattened array of the knot averages + */ +SPLINTER_API double *splinter_bspline_get_knot_averages(splinter_obj_ptr bspline_ptr); + +/** + * Get the basis degrees of the BSpline + * Returns an array of size splinter_bspline_get_num_variables + * + * @param bspline_ptr Pointer to the BSpline + * @return Array of basis degrees + */ +SPLINTER_API int *splinter_bspline_get_basis_degrees(splinter_obj_ptr bspline_ptr); + +/** + * Evaluate a BSpline in one or more points. Can "batch evaluate" several points by storing the points consecutively in + * x in row major order. If function is a two-dimensional function you can evaluate the function in x0 = [0, 1] and + * x1 = [2, 3] in one function call by having x point to the start of an array of four doubles: 0 1 2 3, and x_len = 4. + * This function will then return an array of 2 doubles, the first being the result of evaluating the function in [0, 1], + * and the second being the result of evaluating the function in [2, 3]. + * + * If the function is multi-dimensional in the codomain, the results are flattened so that the result of evaluating + * the first point comes first, then the second, etc. + * + * @param bspline_ptr Pointer to the BSpline to evaluate. + * @param xs Array of doubles. Is of x_len length. + * @param x_len Length of x. + * @return Array of results corresponding to the points in x. + */ +SPLINTER_API double *splinter_bspline_eval_row_major(splinter_obj_ptr bspline_ptr, double *xs, int x_len); + +/** + * Evaluate the jacobian of a BSpline in one or more points. + * @see splinter_bspline_eval_row_major() for further explanation of the behaviour. + * + * @param bspline_ptr Pointer to the BSpline to evaluate. + * @param x Array of doubles. Is of x_len length. + * @param x_len Length of x. + * @return Flattened array of array of results corresponding to the points in x. + */ +SPLINTER_API double *splinter_bspline_eval_jacobian_row_major(splinter_obj_ptr bspline_ptr, double *x, int x_len); + +/** + * Evaluate the a BSpline in one or more points that are stored in column major order. + * @see splinter_bspline_eval_row_major() for further explanation of the behaviour. + * + * @param bspline_ptr Pointer to the BSpline to evaluate. + * @param x Array of doubles. Is of x_len length. + * @param x_len Length of x. + * @return Array of results. + */ +SPLINTER_API double *splinter_bspline_eval_col_major(splinter_obj_ptr bspline_ptr, double *x, int x_len); + +/** + * Evaluate the jacobian of a BSpline in one or more points that are stored in column major order. + * @see splinter_bspline_eval_row_major() for further explanation of the behaviour. + * + * @param bspline_ptr Pointer to the BSpline to evaluate. + * @param x Array of doubles. Is of x_len length. + * @param x_len Length of x. + * @return Flattened array of array of results corresponding to the points in x. Stored in ROW major order. + */ +SPLINTER_API double *splinter_bspline_eval_jacobian_col_major(splinter_obj_ptr bspline_ptr, double *x, int x_len); + +/** + * Get the number of inputs of a BSpline (dimension of domain). + * + * @param bspline_ptr Pointer to the BSpline. + */ +SPLINTER_API int splinter_bspline_get_dim_x(splinter_obj_ptr bspline_ptr); + +/** + * Get the number of outputs of a BSpline (dimensions of codomain). + * + * @param bspline_ptr Pointer to the BSpline. + */ +SPLINTER_API int splinter_bspline_get_dim_y(splinter_obj_ptr bspline_ptr); + +/** + * Save a BSpline to json file. + * + * @param bspline_ptr Pointer to the BSpline + * @param filename File to save the BSpline to (will be overwritten!) + */ +SPLINTER_API void splinter_bspline_to_json(splinter_obj_ptr bspline_ptr, const char *filename); + +/** + * Load a BSpline to json file. + * + * @param bspline_ptr Pointer to the BSpline + * @param filename File to save the BSpline to (will be overwritten!) + */ +SPLINTER_API splinter_obj_ptr splinter_bspline_from_json(const char *filename); + +/** + * Free the memory used by a BSpline. + * + * @param bspline_ptr Pointer to the BSpline. + */ +SPLINTER_API void splinter_bspline_delete(splinter_obj_ptr bspline_ptr); + +/** + * Insert knots at tau of multiplicity 'multiplicity' to knot vector in variable 'dim'. The B-spline is geometrically + * unaltered by the knot insertion. + * + * @param bspline_ptr Pointer to the BSpline to evaluate. + * @param tau Knot to insert + * @param dim Knot vector to insert knots + * @param multiplicity Desired multiplicity of knot + */ +SPLINTER_API void splinter_bspline_insert_knots(splinter_obj_ptr bspline_ptr, double tau, unsigned int dim, + unsigned int multiplicity); + +/** + * Insert knots until all knots have multiplicity equal to the B-spline degree. + * + * @param bspline_ptr Pointer to the BSpline to decompose to Bezier form + */ +SPLINTER_API void splinter_bspline_decompose_to_bezier_form(splinter_obj_ptr bspline_ptr); + +/** + * Make a copy of a BSpline. + * + * @param bspline_ptr + * @return The new copy + */ +SPLINTER_API splinter_obj_ptr splinter_bspline_copy(splinter_obj_ptr bspline_ptr); + +/** + * Fit BSpline to data. + * + * @param bspline_ptr The BSpline to fit. + * @param datatable_ptr The datatable with data. + * @param smoothing Smoothing type (actually an enum, see the implementation of this function for details) + * @param alpha Regularization/smoothing parameter (must be non-negative). + * @param weights Weights to apply to data points. + * @param num_weights Number of weights. + * @return Pointer to the created BSpline. + */ +SPLINTER_API splinter_obj_ptr splinter_bspline_fit(splinter_obj_ptr bspline_ptr, + splinter_obj_ptr datatable_ptr, + int smoothing, + double alpha, + double *weights, + int num_weights); + +#ifdef __cplusplus + } +#endif + +#endif // SPLINTER_CINTERFACE_H diff --git a/splinter/include/cinterface/utilities.h b/splinter/include/cinterface/utilities.h new file mode 100644 index 0000000000..c143c606b8 --- /dev/null +++ b/splinter/include/cinterface/utilities.h @@ -0,0 +1,172 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#ifndef SPLINTER_UTILITIES_H +#define SPLINTER_UTILITIES_H + +#include "data_table.h" +#include "function.h" +#include "cinterface.h" +#include "bspline.h" +#include "knot_builders.h" +#include + + +namespace SPLINTER +{ + +// Declare the global variables for use in all source files +// All extern variables are defined in cinterface/utilities.cpp +// Keep a list of objects so we avoid performing operations on objects that don't exist +extern std::set datatables; +extern std::set bsplines; + +extern int splinter_last_func_call_error; // Tracks the success of the last function call +extern const char *splinter_error_string; // Error string (if the last function call resulted in an error) + +void set_error_string(const char *new_error_string); + +/* Check for existence of datatable_ptr, then cast splinter_obj_ptr to a DataTable * */ +DataTable *get_datatable(splinter_obj_ptr datatable_ptr); + +/* Check for existence of bspline_ptr, then cast splinter_obj_ptr to a BSpline * */ +BSpline *get_bspline(splinter_obj_ptr bspline_ptr); + +// Convert int to Smoothing +BSpline::Smoothing resolve_smoothing(int smoothing); + +// Convert int to KnotSpacing +KnotSpacing resolve_knot_spacing(int knot_spacing); + +/** + * Convert from column major to row major with point_dim number of columns. + * + * @param col_major Column major data + * @param point_dim Dimension of each point (= number of columns) + * @return col_major data stored row major. + */ +double *get_row_major(double *col_major, size_t point_dim, size_t x_len); + +/** + * Convert from standard C array to DenseVector. + * + * @param x C array to convert from. + * @param x_dim The size of x. + * @return DenseVector with the same data as x. + */ +template +DenseVector get_densevector(NUMERICAL_TYPE *x, size_t x_dim) +{ + DenseVector xvec(x_dim); + for (size_t i = 0; i < x_dim; i++) + { + xvec(i) = (double) x[i]; + } + + return xvec; +} + +/** + * Convert from DenseVector to a vector of NUMERICAL_TYPE. + * It must be possible to cast from double to NUMERICAL_TYPE. + * + * @param x DenseVector to convert from. + * @return Vector with the same data as x. + */ +template +std::vector get_vector(DenseVector x) +{ + auto vector = std::vector(x.size()); + for (size_t i = 0; i < x.size(); ++i) + { + vector.at(i) = (NUMERICAL_TYPE) x(i); + } + + return vector; +} + +/** + * Convert from pointer to NUMERICAL_TYPE to std::vector + * + * @param array Pointer to NUMERICAL_TYPE + * @param n Number of elements to copy + * @return std::vector with the same elements as in array + */ +template +std::vector get_vector(NUMERICAL_TYPE *array, int n) +{ + return std::vector(array, array + n); +} + +/** + * Convert from pointer to NUMERICAL_TYPE to std::vector> + * Number of values copied: num_per_row[0] * num_per_row[1] * ... * num_per_row[num_rows - 1] + * + * @param array Pointer to NUMERICAL_TYPE + * @param num_per_row Number of elements per row + * @param num_rows Number of rows + * @return std::vector with the same elements as in array + */ +template +std::vector> get_vector_vector(NUMERICAL_TYPE *array, unsigned int *num_per_row, + unsigned int num_rows) +{ + auto num_per_row_as_vec = std::vector(num_per_row, num_per_row + num_rows); + + auto vec_vec = std::vector>(num_rows); + + int k = 0; + for (unsigned int i = 0; i < num_rows; ++i) + { + unsigned int num_row_i = num_per_row_as_vec.at(i); + std::vector vec(num_row_i); + for (unsigned int j = 0; j < num_row_i; ++j) + { + vec.at(j) = array[k]; + k++; + } + vec_vec.at(i) = vec; + } + + return vec_vec; +} + +/** + * Convert from pointer to NUMERICAL_TYPE to std::vector> + * Number of values copied: num_per_row*num_rows + * + * @param array Pointer to NUMERICAL_TYPE + * @param num_per_row Number of elements per row (constant) + * @param num_rows Number of rows + * @return std::vector with the same elements as in array + */ +template +std::vector> get_vector_vector(NUMERICAL_TYPE *array, unsigned int num_per_row, + unsigned int num_rows) +{ + auto vec_vec = std::vector>(num_rows); + + unsigned int k = 0; + for (unsigned int i = 0; i < num_rows; ++i) + { + std::vector vec(num_per_row); + for (unsigned int j = 0; j < num_per_row; ++j) + { + vec.at(j) = array[k]; + k++; + } + vec_vec.at(i) = vec; + } + + return vec_vec; +} + +} // namespace SPLINTER + +#endif // SPLINTER_UTILITIES_H diff --git a/splinter/include/data_point.h b/splinter/include/data_point.h new file mode 100644 index 0000000000..99487754a1 --- /dev/null +++ b/splinter/include/data_point.h @@ -0,0 +1,61 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#ifndef SPLINTER_DATA_POINT_H +#define SPLINTER_DATA_POINT_H + +#include "definitions.h" + +namespace SPLINTER +{ + +/* + * DataPoint is a class representing a data point (x, y), where y is the value obtained by sampling at a point x. + * Note that x and y may be a scalar or vector. + */ +class DataPoint +{ +public: + DataPoint(double x, double y); + DataPoint(const std::vector &x, double y); + DataPoint(double x, const std::vector &y); + DataPoint(const std::vector &x, const std::vector &y); + + /** + * Getters + */ + std::vector get_x() const { + return x; + } + + std::vector get_y() const { + return y; + } + + unsigned int get_dim_x() const { + return (unsigned int) x.size(); + } + + unsigned int get_dim_y() const { + return (unsigned int) y.size(); + } + + bool operator<(const DataPoint &rhs) const; // Returns false if the two are equal + +private: + DataPoint() {}; + + std::vector x; + std::vector y; + void set_data(const std::vector &x, const std::vector &y); +}; + +} // namespace SPLINTER + +#endif // SPLINTER_DATA_POINT_H diff --git a/splinter/include/data_table.h b/splinter/include/data_table.h new file mode 100644 index 0000000000..7d453aab3a --- /dev/null +++ b/splinter/include/data_table.h @@ -0,0 +1,117 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#ifndef SPLINTER_DATA_TABLE_H +#define SPLINTER_DATA_TABLE_H + +#include "data_point.h" +#include +#include + + +namespace SPLINTER +{ + +/* + * DataTable is a class for storing multidimensional data samples (x, y). + * The samples are stored in a vector with properties: + * - Elements can be stored in any order (no sorted order) + * - Duplicates are allowed (DataPoint x-values determines uniqueness) + */ +class SPLINTER_API DataTable +{ +public: + DataTable() : _dim_x(1), _dim_y(1) {} + + /* + * Functions for adding a sample (x, y) + */ + void add_sample(const DataPoint &sample); + + void add_sample(std::initializer_list samples); + + template + void add_sample(Tx x, Ty y) { + return add_sample(DataPoint(x, y)); + } + + template + void add_sample(std::initializer_list x, Ty y) { + return add_sample(DataPoint(x, y)); + } + + template + void add_sample(Tx x, std::initializer_list y) { + return add_sample(DataPoint(x, y)); + } + + template + void add_sample(std::initializer_list x, std::initializer_list y) { + return add_sample(DataPoint(x, y)); + } + + /* + * Getters + */ + std::vector::const_iterator cbegin() const { + return samples.cbegin(); + } + + std::vector::const_iterator cend() const { + return samples.cend(); + } + + unsigned int get_dim_x() const { + return _dim_x; + } + + unsigned int get_dim_y() const { + return _dim_y; + } + + unsigned int get_num_samples() const { + return (unsigned int) samples.size(); + } + + const std::vector& get_samples() const { + return samples; + } + + std::vector> get_table_x() const; + + std::vector> get_table_y() const; + + /** + * Save and load + */ + void to_json(const std::string &filename) const { + SPLINTER::datatable_to_json(*this, filename); + } + + static DataTable from_json(const std::string &filename) { + return SPLINTER::datatable_from_json(filename); + } + + /** + * Utilities + */ + bool is_grid_complete() const; + +private: + unsigned int _dim_x; + unsigned int _dim_y; + std::vector samples; + + friend bool operator==(const DataTable &lhs, const DataTable &rhs); +// friend void datatable_to_json(const DataTable &data, const std::string &filename); +}; + +} // namespace SPLINTER + +#endif // SPLINTER_DATA_TABLE_H diff --git a/splinter/definitions.h b/splinter/include/definitions.h similarity index 51% rename from splinter/definitions.h rename to splinter/include/definitions.h index 068902df52..f788f70df5 100644 --- a/splinter/definitions.h +++ b/splinter/include/definitions.h @@ -30,24 +30,23 @@ # include #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push -// fails CentOS 7 #pragma GCC diagnostic ignored "-Wignored-attributes" +// #pragma GCC diagnostic ignored "-Wignored-attributes" #endif -//# include -#include "Core" -#include "LU" -#include "Cholesky" -#include "QR" -#include "SVD" -#include "Geometry" -#include "Eigenvalues" +#include +#include +#include +#include +#include +#include +#include //# include -#include "SparseCore" -#include "OrderingMethods" -#include "SparseCholesky" -#include "SparseLU" -#include "SparseQR" -#include "IterativeLinearSolvers" +#include +#include +#include +#include +#include +#include #include @@ -55,9 +54,6 @@ #include #include #include - - - #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif @@ -65,31 +61,31 @@ namespace SPLINTER { -// Eigen vectors -typedef Eigen::VectorXd DenseVector; -typedef Eigen::SparseVector SparseVector; + // Eigen vectors + typedef Eigen::VectorXd DenseVector; + typedef Eigen::SparseVector SparseVector; -// Eigen matrices -typedef Eigen::MatrixXd DenseMatrix; -typedef Eigen::SparseMatrix SparseMatrix; // declares a column-major sparse matrix type of double + // Eigen matrices + typedef Eigen::MatrixXd DenseMatrix; + typedef Eigen::SparseMatrix SparseMatrix; // declares a column-major sparse matrix type of double -class Exception : public std::exception -{ -private: - std::string __what; + class Exception : public std::exception + { + private: + std::string __what; -public: + public: - Exception(const std::string& what) - : __what(what) - { - } + Exception(const std::string& what) + : __what(what) + { + } - const char* what() const throw() - { - return this->__what.c_str(); - } -}; + const char* what() const throw() + { + return this->__what.c_str(); + } + }; } // namespace SPLINTER diff --git a/splinter/include/function.h b/splinter/include/function.h new file mode 100644 index 0000000000..b4ce0e977a --- /dev/null +++ b/splinter/include/function.h @@ -0,0 +1,95 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#ifndef SPLINTER_FUNCTION_H +#define SPLINTER_FUNCTION_H + +#include "definitions.h" + +namespace SPLINTER +{ + +/* + * Interface for functions f : R^m -> R^n + * All functions working with standard C++11 types are defined in terms of their Eigen counterparts. + * Default implementations of Jacobian uses central differences. + */ +class SPLINTER_API Function +{ +public: + Function() + : Function(1, 1) {} + + Function(unsigned int m, unsigned int n) + : dim_x(m), dim_y(n) {} + + virtual ~Function() {} + + /** + * Returns the (dimY) function values at x + */ + virtual std::vector eval(const std::vector &x) const = 0; + + virtual DenseVector eval(const DenseVector &x) const; + + /** + * Returns the (dimY x dimX) Jacobian evaluated at x + */ + virtual DenseMatrix eval_jacobian(const DenseVector &x) const; + + /** + * Returns the (dimY x dimX) Jacobian evaluated at x + */ + std::vector> eval_jacobian(const std::vector &x) const; + + /** + * Get dimensions + */ + inline unsigned int get_dim_x() const + { + return dim_x; + } + + inline unsigned int get_dim_y() const + { + return dim_y; + } + + /** + * Check input + */ + void check_input(const std::vector &x) const { + if (x.size() != dim_x) + throw Exception("Function::check_input: Wrong dimension on evaluation point x."); + } + + void check_input(const DenseVector &x) const; + + /** + * Returns the central difference at x + */ + DenseMatrix central_difference(const DenseVector &x) const; + + /** + * Description of function. + */ + virtual std::string get_description() const + { + return ""; + } + +protected: + unsigned int dim_x; // Dimension of domain (size of x) + unsigned int dim_y; // Dimension of codomain (size of y) + +}; + +} // namespace SPLINTER + +#endif // SPLINTER_FUNCTION_H \ No newline at end of file diff --git a/splinter/include/json.h b/splinter/include/json.h new file mode 100644 index 0000000000..b7e7952b82 --- /dev/null +++ b/splinter/include/json.h @@ -0,0 +1,17170 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.1.0 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +Copyright (c) 2013-2018 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef NLOHMANN_JSON_HPP +#define NLOHMANN_JSON_HPP + +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 1 +#define NLOHMANN_JSON_VERSION_PATCH 0 + +#include // all_of, find, for_each +#include // assert +#include // and, not, or +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#include // istream, ostream +#include // iterator_traits, random_access_iterator_tag +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap + +// #include +#ifndef NLOHMANN_JSON_FWD_HPP +#define NLOHMANN_JSON_FWD_HPP + +#include // int64_t, uint64_t +#include // map +#include // allocator +#include // string +#include // vector + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer; + +template class ObjectType = +std::map, +template class ArrayType = std::vector, +class StringType = std::string, class BooleanType = bool, +class NumberIntegerType = std::int64_t, +class NumberUnsignedType = std::uint64_t, +class NumberFloatType = double, +template class AllocatorType = std::allocator, +template class JSONSerializer = +adl_serializer> +class basic_json; + +/*! +@brief JSON Pointer + +A JSON pointer defines a string syntax for identifying a specific value +within a JSON document. It can be used with functions `at` and +`operator[]`. Furthermore, JSON pointers are the base for JSON patches. + +@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + +@since version 2.0.0 +*/ +template +class json_pointer; + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; +} + +#endif + +// #include + + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if defined(__clang__) +#if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 +#error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" +#endif +#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) +#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 +#error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" +#endif +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow for portable deprecation warnings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) +#define JSON_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define JSON_DEPRECATED __declspec(deprecated) +#else +#define JSON_DEPRECATED +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) +#define JSON_THROW(exception) throw exception +#define JSON_TRY try +#define JSON_CATCH(exception) catch(exception) +#else +#define JSON_THROW(exception) std::abort() +#define JSON_TRY if(true) +#define JSON_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) +#undef JSON_THROW +#define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) +#undef JSON_TRY +#define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) +#undef JSON_CATCH +#define JSON_CATCH JSON_CATCH_USER +#endif + +// manual branch prediction +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) +#define JSON_LIKELY(x) __builtin_expect(!!(x), 1) +#define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define JSON_LIKELY(x) x +#define JSON_UNLIKELY(x) x +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 +#define JSON_HAS_CPP_17 +#define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) +#define JSON_HAS_CPP_14 +#endif + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +/*! +@brief Helper to determine whether there's a key_type for T. + +This helper is used to tell associative containers apart from other containers +such as sequence containers. For instance, `std::map` passes the test as it +contains a `mapped_type`, whereas `std::vector` fails the test. + +@sa http://stackoverflow.com/a/7728728/266378 +@since version 1.0.0, overworked in version 2.0.6 +*/ +#define NLOHMANN_JSON_HAS_HELPER(type) \ + template struct has_##type { \ + private: \ + template \ + static int detect(U &&); \ + static void detect(...); \ + public: \ + static constexpr bool value = \ + std::is_integral()))>::value; \ + } + +// #include + + +#include // not +#include // size_t +#include // numeric_limits +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // declval + +// #include + +// #include + + +namespace nlohmann +{ +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ +///////////// +// helpers // +///////////// + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ +using type = index_sequence; +using value_type = std::size_t; +static constexpr std::size_t size() noexcept +{ +return sizeof...(Ints); +} +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> +: index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence +: merge_and_renumber < typename make_index_sequence < N / 2 >::type, +typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +/* +Implementation of two C++17 constructs: conjunction, negation. This is needed +to avoid evaluating all the traits in a condition + +For example: not std::is_same::value and has_value_type::value +will not compile when T = void (on MSVC at least). Whereas +conjunction>, has_value_type>::value will +stop evaluating if negation<...>::value == false + +Please note that those constructs must be used with caution, since symbols can +become very long quickly (which can slow down compilation and cause MSVC +internal compiler errors). Only use it when you have to (see example ahead). +*/ +template struct conjunction : std::true_type {}; +template struct conjunction : B1 {}; +template +struct conjunction : std::conditional, B1>::type {}; + +template struct negation : std::integral_constant {}; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +//////////////////////// +// has_/is_ functions // +//////////////////////// + +// source: https://stackoverflow.com/a/37193089/4116453 + +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; + +NLOHMANN_JSON_HAS_HELPER(mapped_type); +NLOHMANN_JSON_HAS_HELPER(key_type); +NLOHMANN_JSON_HAS_HELPER(value_type); +NLOHMANN_JSON_HAS_HELPER(iterator); + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl +{ +static constexpr auto value = +std::is_constructible::value and +std::is_constructible::value; +}; + +template +struct is_compatible_object_type +{ +static auto constexpr value = is_compatible_object_type_impl < +conjunction>, +has_mapped_type, +has_key_type>::value, +typename BasicJsonType::object_t, CompatibleObjectType >::value; +}; + +template +struct is_basic_json_nested_type +{ +static auto constexpr value = std::is_same::value or +std::is_same::value or +std::is_same::value or +std::is_same::value; +}; + +template +struct is_compatible_array_type +{ +static auto constexpr value = +conjunction>, +negation>, +negation>, +negation>, +has_value_type, +has_iterator>::value; +}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl +{ +// is there an assert somewhere on overflows? +using RealLimits = std::numeric_limits; +using CompatibleLimits = std::numeric_limits; + +static constexpr auto value = +std::is_constructible::value and +CompatibleLimits::is_integer and +RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type +{ +static constexpr auto value = +is_compatible_integer_type_impl < +std::is_integral::value and +not std::is_same::value, +RealIntegerType, CompatibleNumberIntegerType > ::value; +}; + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json +{ +private: +// also check the return type of from_json +template::from_json( +std::declval(), std::declval()))>::value>> +static int detect(U&&); +static void detect(...); + +public: +static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json +{ +private: +template < +typename U, +typename = enable_if_t::from_json(std::declval()))>::value >> +static int detect(U&&); +static void detect(...); + +public: +static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +template +struct has_to_json +{ +private: +template::to_json( +std::declval(), std::declval()))> +static int detect(U&&); +static void detect(...); + +public: +static constexpr bool value = std::is_integral>()))>::value; +}; + +template +struct is_compatible_complete_type +{ +static constexpr bool value = +not std::is_base_of::value and +not std::is_same::value and +not is_basic_json_nested_type::value and +has_to_json::value; +}; + +template +struct is_compatible_type +: conjunction, +is_compatible_complete_type> +{ +}; + +// taken from ranges-v3 +template +struct static_const +{ +static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} +} + +// #include + + +#include // exception +#include // runtime_error +#include // to_string + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ +public: +/// returns the explanatory string +const char* what() const noexcept override +{ +return m.what(); +} + +/// the id of the exception +const int id; + +protected: +exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + +static std::string name(const std::string& ename, int id_) +{ +return "[json.exception." + ename + "." + std::to_string(id_) + "] "; +} + +private: +/// an exception object as storage for error messages +std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ +public: +/*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] byte_ the byte index where the error occurred (or 0 if the + position cannot be determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ +static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) +{ +std::string w = exception::name("parse_error", id_) + "parse error" + +(byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + +": " + what_arg; +return parse_error(id_, byte_, w.c_str()); +} + +/*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ +const std::size_t byte; + +private: +parse_error(int id_, std::size_t byte_, const char* what_arg) +: exception(id_, what_arg), byte(byte_) {} +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ +public: +static invalid_iterator create(int id_, const std::string& what_arg) +{ +std::string w = exception::name("invalid_iterator", id_) + what_arg; +return invalid_iterator(id_, w.c_str()); +} + +private: +invalid_iterator(int id_, const char* what_arg) +: exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ +public: +static type_error create(int id_, const std::string& what_arg) +{ +std::string w = exception::name("type_error", id_) + what_arg; +return type_error(id_, w.c_str()); +} + +private: +type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. +json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON only supports integers numbers up to 9223372036854775807. | + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ +public: +static out_of_range create(int id_, const std::string& what_arg) +{ +std::string w = exception::name("out_of_range", id_) + what_arg; +return out_of_range(id_, w.c_str()); +} + +private: +out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ +public: +static other_error create(int id_, const std::string& what_arg) +{ +std::string w = exception::name("other_error", id_) + what_arg; +return other_error(id_, w.c_str()); +} + +private: +other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} +} + +// #include + + +#include // array +#include // and +#include // size_t +#include // uint8_t + +namespace nlohmann +{ +namespace detail +{ +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ +null, ///< null value +object, ///< object (unordered set of name/value pairs) +array, ///< array (ordered collection of values) +string, ///< string value +boolean, ///< boolean value +number_integer, ///< number value (signed integer) +number_unsigned, ///< number value (unsigned integer) +number_float, ///< number value (floating-point) +discarded ///< discarded by the the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string +- furthermore, each type is not smaller than itself +- discarded values are not comparable + +@since version 1.0.0 +*/ +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ +static constexpr std::array order = {{ +0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, +1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ +} +}; + +const auto l_index = static_cast(lhs); +const auto r_index = static_cast(rhs); +return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; +} +} +} + +// #include + + +#include // transform +#include // array +#include // and, not +#include // forward_list +#include // inserter, front_inserter, end +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // pair, declval +#include // valarray + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +// overloads for basic_json template parameters +template::value and +not std::is_same::value, +int> = 0> +void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) +{ +switch (static_cast(j)) +{ +case value_t::number_unsigned: +{ +val = static_cast(*j.template get_ptr()); +break; +} +case value_t::number_integer: +{ +val = static_cast(*j.template get_ptr()); +break; +} +case value_t::number_float: +{ +val = static_cast(*j.template get_ptr()); +break; +} + +default: +JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); +} +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) +{ +if (JSON_UNLIKELY(not j.is_boolean())) +{ +JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); +} +b = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) +{ +if (JSON_UNLIKELY(not j.is_string())) +{ +JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); +} +s = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) +{ +get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) +{ +get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) +{ +get_arithmetic_value(j, val); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, EnumType& e) +{ +typename std::underlying_type::type val; +get_arithmetic_value(j, val); +e = static_cast(val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) +{ +if (JSON_UNLIKELY(not j.is_array())) +{ +JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); +} +arr = *j.template get_ptr(); +} + +// forward_list doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::forward_list& l) +{ +if (JSON_UNLIKELY(not j.is_array())) +{ +JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); +} +std::transform(j.rbegin(), j.rend(), +std::front_inserter(l), [](const BasicJsonType & i) +{ +return i.template get(); +}); +} + +// valarray doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::valarray& l) +{ +if (JSON_UNLIKELY(not j.is_array())) +{ +JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); +} +l.resize(j.size()); +std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); +} + +template +void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/) +{ +using std::end; + +std::transform(j.begin(), j.end(), +std::inserter(arr, end(arr)), [](const BasicJsonType & i) +{ +// get() returns *this, this won't call a from_json +// method when value_type is BasicJsonType +return i.template get(); +}); +} + +template +auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/) +-> decltype( +arr.reserve(std::declval()), +void()) +{ +using std::end; + +arr.reserve(j.size()); +std::transform(j.begin(), j.end(), +std::inserter(arr, end(arr)), [](const BasicJsonType & i) +{ +// get() returns *this, this won't call a from_json +// method when value_type is BasicJsonType +return i.template get(); +}); +} + +template +void from_json_array_impl(const BasicJsonType& j, std::array& arr, priority_tag<2> /*unused*/) +{ +for (std::size_t i = 0; i < N; ++i) +{ +arr[i] = j.at(i).template get(); +} +} + +template::value and +std::is_convertible::value and +not std::is_same::value, int> = 0> +void from_json(const BasicJsonType& j, CompatibleArrayType& arr) +{ +if (JSON_UNLIKELY(not j.is_array())) +{ +JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); +} + +from_json_array_impl(j, arr, priority_tag<2> {}); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, CompatibleObjectType& obj) +{ +if (JSON_UNLIKELY(not j.is_object())) +{ +JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); +} + +auto inner_object = j.template get_ptr(); +using value_type = typename CompatibleObjectType::value_type; +std::transform( +inner_object->begin(), inner_object->end(), +std::inserter(obj, obj.begin()), +[](typename BasicJsonType::object_t::value_type const & p) +{ +return value_type(p.first, p.second.template get()); +}); +} + +// overload for arithmetic types, not chosen for basic_json template arguments +// (BooleanType, etc..); note: Is it really necessary to provide explicit +// overloads for boolean_t etc. in case of a custom BooleanType which is not +// an arithmetic type? +template::value and +not std::is_same::value and +not std::is_same::value and +not std::is_same::value and +not std::is_same::value, +int> = 0> +void from_json(const BasicJsonType& j, ArithmeticType& val) +{ +switch (static_cast(j)) +{ +case value_t::number_unsigned: +{ +val = static_cast(*j.template get_ptr()); +break; +} +case value_t::number_integer: +{ +val = static_cast(*j.template get_ptr()); +break; +} +case value_t::number_float: +{ +val = static_cast(*j.template get_ptr()); +break; +} +case value_t::boolean: +{ +val = static_cast(*j.template get_ptr()); +break; +} + +default: +JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); +} +} + +template +void from_json(const BasicJsonType& j, std::pair& p) +{ +p = {j.at(0).template get(), j.at(1).template get()}; +} + +template +void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence) +{ +t = std::make_tuple(j.at(Idx).template get::type>()...); +} + +template +void from_json(const BasicJsonType& j, std::tuple& t) +{ +from_json_tuple_impl(j, t, index_sequence_for {}); +} + +struct from_json_fn +{ +private: +template +auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const +noexcept(noexcept(from_json(j, val))) +-> decltype(from_json(j, val), void()) +{ +return from_json(j, val); +} + +template +void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept +{ +static_assert(sizeof(BasicJsonType) == 0, +"could not find from_json() method in T's namespace"); +#ifdef _MSC_VER +// MSVC does not show a stacktrace for the above assert +using decayed = uncvref_t; +static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, +"forcing MSVC stacktrace to show which T we're talking about."); +#endif +} + +public: +template +void operator()(const BasicJsonType& j, T& val) const +noexcept(noexcept(std::declval().call(j, val, priority_tag<1> {}))) +{ +return call(j, val, priority_tag<1> {}); +} +}; +} + +/// namespace to hold default `from_json` function +/// to see why this is required: +/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html +namespace +{ +constexpr const auto& from_json = detail::static_const::value; +} +} + +// #include + + +#include // or, and, not +#include // begin, end +#include // tuple, get +#include // is_same, is_constructible, is_floating_point, is_enum, underlying_type +#include // move, forward, declval, pair +#include // valarray +#include // vector + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +////////////////// +// constructors // +////////////////// + +template struct external_constructor; + +template<> +struct external_constructor +{ +template +static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept +{ +j.m_type = value_t::boolean; +j.m_value = b; +j.assert_invariant(); +} +}; + +template<> +struct external_constructor +{ +template +static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) +{ +j.m_type = value_t::string; +j.m_value = s; +j.assert_invariant(); +} + +template +static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) +{ +j.m_type = value_t::string; +j.m_value = std::move(s); +j.assert_invariant(); +} +}; + +template<> +struct external_constructor +{ +template +static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept +{ +j.m_type = value_t::number_float; +j.m_value = val; +j.assert_invariant(); +} +}; + +template<> +struct external_constructor +{ +template +static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept +{ +j.m_type = value_t::number_unsigned; +j.m_value = val; +j.assert_invariant(); +} +}; + +template<> +struct external_constructor +{ +template +static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept +{ +j.m_type = value_t::number_integer; +j.m_value = val; +j.assert_invariant(); +} +}; + +template<> +struct external_constructor +{ +template +static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) +{ +j.m_type = value_t::array; +j.m_value = arr; +j.assert_invariant(); +} + +template +static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) +{ +j.m_type = value_t::array; +j.m_value = std::move(arr); +j.assert_invariant(); +} + +template::value, +int> = 0> +static void construct(BasicJsonType& j, const CompatibleArrayType& arr) +{ +using std::begin; +using std::end; +j.m_type = value_t::array; +j.m_value.array = j.template create(begin(arr), end(arr)); +j.assert_invariant(); +} + +template +static void construct(BasicJsonType& j, const std::vector& arr) +{ +j.m_type = value_t::array; +j.m_value = value_t::array; +j.m_value.array->reserve(arr.size()); +for (const bool x : arr) +{ +j.m_value.array->push_back(x); +} +j.assert_invariant(); +} + +template::value, int> = 0> +static void construct(BasicJsonType& j, const std::valarray& arr) +{ +j.m_type = value_t::array; +j.m_value = value_t::array; +j.m_value.array->resize(arr.size()); +std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); +j.assert_invariant(); +} +}; + +template<> +struct external_constructor +{ +template +static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) +{ +j.m_type = value_t::object; +j.m_value = obj; +j.assert_invariant(); +} + +template +static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) +{ +j.m_type = value_t::object; +j.m_value = std::move(obj); +j.assert_invariant(); +} + +template::value, int> = 0> +static void construct(BasicJsonType& j, const CompatibleObjectType& obj) +{ +using std::begin; +using std::end; + +j.m_type = value_t::object; +j.m_value.object = j.template create(begin(obj), end(obj)); +j.assert_invariant(); +} +}; + +///////////// +// to_json // +///////////// + +template::value, int> = 0> +void to_json(BasicJsonType& j, T b) noexcept +{ +external_constructor::construct(j, b); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleString& s) +{ +external_constructor::construct(j, s); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) +{ +external_constructor::construct(j, std::move(s)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, FloatType val) noexcept +{ +external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept +{ +external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept +{ +external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, EnumType e) noexcept +{ +using underlying_type = typename std::underlying_type::type; +external_constructor::construct(j, static_cast(e)); +} + +template +void to_json(BasicJsonType& j, const std::vector& e) +{ +external_constructor::construct(j, e); +} + +template::value or +std::is_same::value, +int> = 0> +void to_json(BasicJsonType& j, const CompatibleArrayType& arr) +{ +external_constructor::construct(j, arr); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, std::valarray arr) +{ +external_constructor::construct(j, std::move(arr)); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) +{ +external_constructor::construct(j, std::move(arr)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleObjectType& obj) +{ +external_constructor::construct(j, obj); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) +{ +external_constructor::construct(j, std::move(obj)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, T (&arr)[N]) +{ +external_constructor::construct(j, arr); +} + +template +void to_json(BasicJsonType& j, const std::pair& p) +{ +j = {p.first, p.second}; +} + +template +void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence) +{ +j = {std::get(t)...}; +} + +template +void to_json(BasicJsonType& j, const std::tuple& t) +{ +to_json_tuple_impl(j, t, index_sequence_for {}); +} + +struct to_json_fn +{ +private: +template +auto call(BasicJsonType& j, T&& val, priority_tag<1> /*unused*/) const noexcept(noexcept(to_json(j, std::forward(val)))) +-> decltype(to_json(j, std::forward(val)), void()) +{ +return to_json(j, std::forward(val)); +} + +template +void call(BasicJsonType& /*unused*/, T&& /*unused*/, priority_tag<0> /*unused*/) const noexcept +{ +static_assert(sizeof(BasicJsonType) == 0, +"could not find to_json() method in T's namespace"); + +#ifdef _MSC_VER +// MSVC does not show a stacktrace for the above assert +using decayed = uncvref_t; +static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, +"forcing MSVC stacktrace to show which T we're talking about."); +#endif +} + +public: +template +void operator()(BasicJsonType& j, T&& val) const +noexcept(noexcept(std::declval().call(j, std::forward(val), priority_tag<1> {}))) +{ +return call(j, std::forward(val), priority_tag<1> {}); +} +}; +} + +/// namespace to hold default `to_json` function +namespace +{ +constexpr const auto& to_json = detail::static_const::value; +} +} + +// #include + + +#include // min +#include // array +#include // assert +#include // size_t +#include // strlen +#include // streamsize, streamoff, streampos +#include // istream +#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next +#include // shared_ptr, make_shared, addressof +#include // accumulate +#include // string, char_traits +#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer +#include // pair, declval + +// #include + + +namespace nlohmann +{ +namespace detail +{ +//////////////////// +// input adapters // +//////////////////// + +/*! +@brief abstract input adapter interface + +Produces a stream of std::char_traits::int_type characters from a +std::istream, a buffer, or some other input type. Accepts the return of exactly +one non-EOF character for future input. The int_type characters returned +consist of all valid char values as positive values (typically unsigned char), +plus an EOF value outside that range, specified by the value of the function +std::char_traits::eof(). This value is typically -1, but could be any +arbitrary value which is not a valid char value. +*/ +struct input_adapter_protocol +{ +/// get a character [0,255] or std::char_traits::eof(). +virtual std::char_traits::int_type get_character() = 0; +/// restore the last non-eof() character to input +virtual void unget_character() = 0; +virtual ~input_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +using input_adapter_t = std::shared_ptr; + +/*! +Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at +beginning of input. Does not support changing the underlying std::streambuf +in mid-input. Maintains underlying std::istream and std::streambuf to support +subsequent use of standard std::istream operations to process any input +characters following those used in parsing the JSON input. Clears the +std::istream flags; any input errors (e.g., EOF) will be detected by the first +subsequent call for input from the std::istream. +*/ +class input_stream_adapter : public input_adapter_protocol +{ +public: +~input_stream_adapter() override +{ +// clear stream flags; we use underlying streambuf I/O, do not +// maintain ifstream flags +is.clear(); +} + +explicit input_stream_adapter(std::istream& i) +: is(i), sb(*i.rdbuf()) +{ +// skip byte order mark +std::char_traits::int_type c; +if ((c = get_character()) == 0xEF) +{ +if ((c = get_character()) == 0xBB) +{ +if ((c = get_character()) == 0xBF) +{ +return; // Ignore BOM +} +else if (c != std::char_traits::eof()) +{ +is.unget(); +} +is.putback('\xBB'); +} +else if (c != std::char_traits::eof()) +{ +is.unget(); +} +is.putback('\xEF'); +} +else if (c != std::char_traits::eof()) +{ +is.unget(); // no byte order mark; process as usual +} +} + +// delete because of pointer members +input_stream_adapter(const input_stream_adapter&) = delete; +input_stream_adapter& operator=(input_stream_adapter&) = delete; + +// std::istream/std::streambuf use std::char_traits::to_int_type, to +// ensure that std::char_traits::eof() and the character 0xFF do not +// end up as the same value, eg. 0xFFFFFFFF. +std::char_traits::int_type get_character() override +{ +return sb.sbumpc(); +} + +void unget_character() override +{ +sb.sungetc(); // is.unget() avoided for performance +} + +private: +/// the associated input stream +std::istream& is; +std::streambuf& sb; +}; + +/// input adapter for buffer input +class input_buffer_adapter : public input_adapter_protocol +{ +public: +input_buffer_adapter(const char* b, const std::size_t l) +: cursor(b), limit(b + l), start(b) +{ +// skip byte order mark +if (l >= 3 and b[0] == '\xEF' and b[1] == '\xBB' and b[2] == '\xBF') +{ +cursor += 3; +} +} + +// delete because of pointer members +input_buffer_adapter(const input_buffer_adapter&) = delete; +input_buffer_adapter& operator=(input_buffer_adapter&) = delete; + +std::char_traits::int_type get_character() noexcept override +{ +if (JSON_LIKELY(cursor < limit)) +{ +return std::char_traits::to_int_type(*(cursor++)); +} + +return std::char_traits::eof(); +} + +void unget_character() noexcept override +{ +if (JSON_LIKELY(cursor > start)) +{ +--cursor; +} +} + +private: +/// pointer to the current character +const char* cursor; +/// pointer past the last character +const char* limit; +/// pointer to the first character +const char* start; +}; + +class input_adapter +{ +public: +// native support + +/// input adapter for input stream +input_adapter(std::istream& i) +: ia(std::make_shared(i)) {} + +/// input adapter for input stream +input_adapter(std::istream&& i) +: ia(std::make_shared(i)) {} + +/// input adapter for buffer +template::value and +std::is_integral::type>::value and +sizeof(typename std::remove_pointer::type) == 1, +int>::type = 0> +input_adapter(CharT b, std::size_t l) +: ia(std::make_shared(reinterpret_cast(b), l)) {} + +// derived support + +/// input adapter for string literal +template::value and +std::is_integral::type>::value and +sizeof(typename std::remove_pointer::type) == 1, +int>::type = 0> +input_adapter(CharT b) +: input_adapter(reinterpret_cast(b), +std::strlen(reinterpret_cast(b))) {} + +/// input adapter for iterator range with contiguous storage +template::iterator_category, std::random_access_iterator_tag>::value, +int>::type = 0> +input_adapter(IteratorType first, IteratorType last) +{ +// assertion to check that the iterator range is indeed contiguous, +// see http://stackoverflow.com/a/35008842/266378 for more discussion +assert(std::accumulate( +first, last, std::pair(true, 0), +[&first](std::pair res, decltype(*first) val) +{ +res.first &= (val == *(std::next(std::addressof(*first), res.second++))); +return res; +}).first); + +// assertion to check that each element is 1 byte long +static_assert( +sizeof(typename std::iterator_traits::value_type) == 1, +"each element in the iterator range must have the size of 1 byte"); + +const auto len = static_cast(std::distance(first, last)); +if (JSON_LIKELY(len > 0)) +{ +// there is at least one element: use the address of first +ia = std::make_shared(reinterpret_cast(&(*first)), len); +} +else +{ +// the address of first cannot be used: use nullptr +ia = std::make_shared(nullptr, len); +} +} + +/// input adapter for array +template +input_adapter(T (&array)[N]) +: input_adapter(std::begin(array), std::end(array)) {} + +/// input adapter for contiguous container +template::value and +std::is_base_of()))>::iterator_category>::value, +int>::type = 0> +input_adapter(const ContiguousContainer& c) +: input_adapter(std::begin(c), std::end(c)) {} + +operator input_adapter_t() +{ +return ia; +} + +private: +/// the actual adapter +input_adapter_t ia = nullptr; +}; +} +} + +// #include + + +#include // localeconv +#include // size_t +#include // strtof, strtod, strtold, strtoll, strtoull +#include // initializer_list +#include // hex, uppercase +#include // setw, setfill +#include // stringstream +#include // char_traits, string +#include // vector + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////// +// lexer // +/////////// + +/*! +@brief lexical analysis + +This class organizes the lexical analysis during JSON deserialization. +*/ +template +class lexer +{ +using number_integer_t = typename BasicJsonType::number_integer_t; +using number_unsigned_t = typename BasicJsonType::number_unsigned_t; +using number_float_t = typename BasicJsonType::number_float_t; + +public: +/// token types for the parser +enum class token_type +{ +uninitialized, ///< indicating the scanner is uninitialized +literal_true, ///< the `true` literal +literal_false, ///< the `false` literal +literal_null, ///< the `null` literal +value_string, ///< a string -- use get_string() for actual value +value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value +value_integer, ///< a signed integer -- use get_number_integer() for actual value +value_float, ///< an floating point number -- use get_number_float() for actual value +begin_array, ///< the character for array begin `[` +begin_object, ///< the character for object begin `{` +end_array, ///< the character for array end `]` +end_object, ///< the character for object end `}` +name_separator, ///< the name separator `:` +value_separator, ///< the value separator `,` +parse_error, ///< indicating a parse error +end_of_input, ///< indicating the end of the input buffer +literal_or_value ///< a literal or the begin of a value (only for diagnostics) +}; + +/// return name of values of type token_type (only used for errors) +static const char* token_type_name(const token_type t) noexcept +{ +switch (t) +{ +case token_type::uninitialized: +return ""; +case token_type::literal_true: +return "true literal"; +case token_type::literal_false: +return "false literal"; +case token_type::literal_null: +return "null literal"; +case token_type::value_string: +return "string literal"; +case lexer::token_type::value_unsigned: +case lexer::token_type::value_integer: +case lexer::token_type::value_float: +return "number literal"; +case token_type::begin_array: +return "'['"; +case token_type::begin_object: +return "'{'"; +case token_type::end_array: +return "']'"; +case token_type::end_object: +return "'}'"; +case token_type::name_separator: +return "':'"; +case token_type::value_separator: +return "','"; +case token_type::parse_error: +return ""; +case token_type::end_of_input: +return "end of input"; +case token_type::literal_or_value: +return "'[', '{', or a literal"; +default: // catch non-enum values +return "unknown token"; // LCOV_EXCL_LINE +} +} + +explicit lexer(detail::input_adapter_t adapter) +: ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} + +// delete because of pointer members +lexer(const lexer&) = delete; +lexer& operator=(lexer&) = delete; + +private: +///////////////////// +// locales +///////////////////// + +/// return the locale-dependent decimal point +static char get_decimal_point() noexcept +{ +const auto loc = localeconv(); +assert(loc != nullptr); +return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); +} + +///////////////////// +// scan functions +///////////////////// + +/*! + @brief get codepoint from 4 hex characters following `\u` + + For input "\u c1 c2 c3 c4" the codepoint is: + (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 + = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) + + Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' + must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The + conversion is done by subtracting the offset (0x30, 0x37, and 0x57) + between the ASCII value of the character and the desired integer value. + + @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or + non-hex character) + */ +int get_codepoint() +{ +// this function only makes sense after reading `\u` +assert(current == 'u'); +int codepoint = 0; + +const auto factors = { 12, 8, 4, 0 }; +for (const auto factor : factors) +{ +get(); + +if (current >= '0' and current <= '9') +{ +codepoint += ((current - 0x30) << factor); +} +else if (current >= 'A' and current <= 'F') +{ +codepoint += ((current - 0x37) << factor); +} +else if (current >= 'a' and current <= 'f') +{ +codepoint += ((current - 0x57) << factor); +} +else +{ +return -1; +} +} + +assert(0x0000 <= codepoint and codepoint <= 0xFFFF); +return codepoint; +} + +/*! + @brief check if the next byte(s) are inside a given range + + Adds the current byte and, for each passed range, reads a new byte and + checks if it is inside the range. If a violation was detected, set up an + error message and return false. Otherwise, return true. + + @param[in] ranges list of integers; interpreted as list of pairs of + inclusive lower and upper bound, respectively + + @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, + 1, 2, or 3 pairs. This precondition is enforced by an assertion. + + @return true if and only if no range violation was detected + */ +bool next_byte_in_range(std::initializer_list ranges) +{ +assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); +add(current); + +for (auto range = ranges.begin(); range != ranges.end(); ++range) +{ +get(); +if (JSON_LIKELY(*range <= current and current <= *(++range))) +{ +add(current); +} +else +{ +error_message = "invalid string: ill-formed UTF-8 byte"; +return false; +} +} + +return true; +} + +/*! + @brief scan a string literal + + This function scans a string according to Sect. 7 of RFC 7159. While + scanning, bytes are escaped and copied into buffer token_buffer. Then the + function returns successfully, token_buffer is *not* null-terminated (as it + may contain \0 bytes), and token_buffer.size() is the number of bytes in the + string. + + @return token_type::value_string if string could be successfully scanned, + token_type::parse_error otherwise + + @note In case of errors, variable error_message contains a textual + description. + */ +token_type scan_string() +{ +// reset token_buffer (ignore opening quote) +reset(); + +// we entered the function by reading an open quote +assert(current == '\"'); + +while (true) +{ +// get next character +switch (get()) +{ +// end of file while parsing string +case std::char_traits::eof(): +{ +error_message = "invalid string: missing closing quote"; +return token_type::parse_error; +} + +// closing quote +case '\"': +{ +return token_type::value_string; +} + +// escapes +case '\\': +{ +switch (get()) +{ +// quotation mark +case '\"': +add('\"'); +break; +// reverse solidus +case '\\': +add('\\'); +break; +// solidus +case '/': +add('/'); +break; +// backspace +case 'b': +add('\b'); +break; +// form feed +case 'f': +add('\f'); +break; +// line feed +case 'n': +add('\n'); +break; +// carriage return +case 'r': +add('\r'); +break; +// tab +case 't': +add('\t'); +break; + +// unicode escapes +case 'u': +{ +const int codepoint1 = get_codepoint(); +int codepoint = codepoint1; // start with codepoint1 + +if (JSON_UNLIKELY(codepoint1 == -1)) +{ +error_message = "invalid string: '\\u' must be followed by 4 hex digits"; +return token_type::parse_error; +} + +// check if code point is a high surrogate +if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) +{ +// expect next \uxxxx entry +if (JSON_LIKELY(get() == '\\' and get() == 'u')) +{ +const int codepoint2 = get_codepoint(); + +if (JSON_UNLIKELY(codepoint2 == -1)) +{ +error_message = "invalid string: '\\u' must be followed by 4 hex digits"; +return token_type::parse_error; +} + +// check if codepoint2 is a low surrogate +if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) +{ +// overwrite codepoint +codepoint = +// high surrogate occupies the most significant 22 bits +(codepoint1 << 10) +// low surrogate occupies the least significant 15 bits ++ codepoint2 +// there is still the 0xD800, 0xDC00 and 0x10000 noise +// in the result so we have to subtract with: +// (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 +- 0x35FDC00; +} +else +{ +error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; +return token_type::parse_error; +} +} +else +{ +error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; +return token_type::parse_error; +} +} +else +{ +if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) +{ +error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; +return token_type::parse_error; +} +} + +// result of the above calculation yields a proper codepoint +assert(0x00 <= codepoint and codepoint <= 0x10FFFF); + +// translate codepoint into bytes +if (codepoint < 0x80) +{ +// 1-byte characters: 0xxxxxxx (ASCII) +add(codepoint); +} +else if (codepoint <= 0x7FF) +{ +// 2-byte characters: 110xxxxx 10xxxxxx +add(0xC0 | (codepoint >> 6)); +add(0x80 | (codepoint & 0x3F)); +} +else if (codepoint <= 0xFFFF) +{ +// 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx +add(0xE0 | (codepoint >> 12)); +add(0x80 | ((codepoint >> 6) & 0x3F)); +add(0x80 | (codepoint & 0x3F)); +} +else +{ +// 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx +add(0xF0 | (codepoint >> 18)); +add(0x80 | ((codepoint >> 12) & 0x3F)); +add(0x80 | ((codepoint >> 6) & 0x3F)); +add(0x80 | (codepoint & 0x3F)); +} + +break; +} + +// other characters after escape +default: +error_message = "invalid string: forbidden character after backslash"; +return token_type::parse_error; +} + +break; +} + +// invalid control characters +case 0x00: +case 0x01: +case 0x02: +case 0x03: +case 0x04: +case 0x05: +case 0x06: +case 0x07: +case 0x08: +case 0x09: +case 0x0A: +case 0x0B: +case 0x0C: +case 0x0D: +case 0x0E: +case 0x0F: +case 0x10: +case 0x11: +case 0x12: +case 0x13: +case 0x14: +case 0x15: +case 0x16: +case 0x17: +case 0x18: +case 0x19: +case 0x1A: +case 0x1B: +case 0x1C: +case 0x1D: +case 0x1E: +case 0x1F: +{ +error_message = "invalid string: control character must be escaped"; +return token_type::parse_error; +} + +// U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) +case 0x20: +case 0x21: +case 0x23: +case 0x24: +case 0x25: +case 0x26: +case 0x27: +case 0x28: +case 0x29: +case 0x2A: +case 0x2B: +case 0x2C: +case 0x2D: +case 0x2E: +case 0x2F: +case 0x30: +case 0x31: +case 0x32: +case 0x33: +case 0x34: +case 0x35: +case 0x36: +case 0x37: +case 0x38: +case 0x39: +case 0x3A: +case 0x3B: +case 0x3C: +case 0x3D: +case 0x3E: +case 0x3F: +case 0x40: +case 0x41: +case 0x42: +case 0x43: +case 0x44: +case 0x45: +case 0x46: +case 0x47: +case 0x48: +case 0x49: +case 0x4A: +case 0x4B: +case 0x4C: +case 0x4D: +case 0x4E: +case 0x4F: +case 0x50: +case 0x51: +case 0x52: +case 0x53: +case 0x54: +case 0x55: +case 0x56: +case 0x57: +case 0x58: +case 0x59: +case 0x5A: +case 0x5B: +case 0x5D: +case 0x5E: +case 0x5F: +case 0x60: +case 0x61: +case 0x62: +case 0x63: +case 0x64: +case 0x65: +case 0x66: +case 0x67: +case 0x68: +case 0x69: +case 0x6A: +case 0x6B: +case 0x6C: +case 0x6D: +case 0x6E: +case 0x6F: +case 0x70: +case 0x71: +case 0x72: +case 0x73: +case 0x74: +case 0x75: +case 0x76: +case 0x77: +case 0x78: +case 0x79: +case 0x7A: +case 0x7B: +case 0x7C: +case 0x7D: +case 0x7E: +case 0x7F: +{ +add(current); +break; +} + +// U+0080..U+07FF: bytes C2..DF 80..BF +case 0xC2: +case 0xC3: +case 0xC4: +case 0xC5: +case 0xC6: +case 0xC7: +case 0xC8: +case 0xC9: +case 0xCA: +case 0xCB: +case 0xCC: +case 0xCD: +case 0xCE: +case 0xCF: +case 0xD0: +case 0xD1: +case 0xD2: +case 0xD3: +case 0xD4: +case 0xD5: +case 0xD6: +case 0xD7: +case 0xD8: +case 0xD9: +case 0xDA: +case 0xDB: +case 0xDC: +case 0xDD: +case 0xDE: +case 0xDF: +{ +if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) +{ +return token_type::parse_error; +} +break; +} + +// U+0800..U+0FFF: bytes E0 A0..BF 80..BF +case 0xE0: +{ +if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) +{ +return token_type::parse_error; +} +break; +} + +// U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF +// U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF +case 0xE1: +case 0xE2: +case 0xE3: +case 0xE4: +case 0xE5: +case 0xE6: +case 0xE7: +case 0xE8: +case 0xE9: +case 0xEA: +case 0xEB: +case 0xEC: +case 0xEE: +case 0xEF: +{ +if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) +{ +return token_type::parse_error; +} +break; +} + +// U+D000..U+D7FF: bytes ED 80..9F 80..BF +case 0xED: +{ +if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) +{ +return token_type::parse_error; +} +break; +} + +// U+10000..U+3FFFF F0 90..BF 80..BF 80..BF +case 0xF0: +{ +if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) +{ +return token_type::parse_error; +} +break; +} + +// U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF +case 0xF1: +case 0xF2: +case 0xF3: +{ +if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) +{ +return token_type::parse_error; +} +break; +} + +// U+100000..U+10FFFF F4 80..8F 80..BF 80..BF +case 0xF4: +{ +if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) +{ +return token_type::parse_error; +} +break; +} + +// remaining bytes (80..C1 and F5..FF) are ill-formed +default: +{ +error_message = "invalid string: ill-formed UTF-8 byte"; +return token_type::parse_error; +} +} +} +} + +static void strtof(float& f, const char* str, char** endptr) noexcept +{ +f = std::strtof(str, endptr); +} + +static void strtof(double& f, const char* str, char** endptr) noexcept +{ +f = std::strtod(str, endptr); +} + +static void strtof(long double& f, const char* str, char** endptr) noexcept +{ +f = std::strtold(str, endptr); +} + +/*! + @brief scan a number literal + + This function scans a string according to Sect. 6 of RFC 7159. + + The function is realized with a deterministic finite state machine derived + from the grammar described in RFC 7159. Starting in state "init", the + input is read and used to determined the next state. Only state "done" + accepts the number. State "error" is a trap state to model errors. In the + table below, "anything" means any character but the ones listed before. + + state | 0 | 1-9 | e E | + | - | . | anything + ---------|----------|----------|----------|---------|---------|----------|----------- + init | zero | any1 | [error] | [error] | minus | [error] | [error] + minus | zero | any1 | [error] | [error] | [error] | [error] | [error] + zero | done | done | exponent | done | done | decimal1 | done + any1 | any1 | any1 | exponent | done | done | decimal1 | done + decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error] + decimal2 | decimal2 | decimal2 | exponent | done | done | done | done + exponent | any2 | any2 | [error] | sign | sign | [error] | [error] + sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] + any2 | any2 | any2 | done | done | done | done | done + + The state machine is realized with one label per state (prefixed with + "scan_number_") and `goto` statements between them. The state machine + contains cycles, but any cycle can be left when EOF is read. Therefore, + the function is guaranteed to terminate. + + During scanning, the read bytes are stored in token_buffer. This string is + then converted to a signed integer, an unsigned integer, or a + floating-point number. + + @return token_type::value_unsigned, token_type::value_integer, or + token_type::value_float if number could be successfully scanned, + token_type::parse_error otherwise + + @note The scanner is independent of the current locale. Internally, the + locale's decimal point is used instead of `.` to work with the + locale-dependent converters. + */ +token_type scan_number() +{ +// reset token_buffer to store the number's bytes +reset(); + +// the type of the parsed number; initially set to unsigned; will be +// changed if minus sign, decimal point or exponent is read +token_type number_type = token_type::value_unsigned; + +// state (init): we just found out we need to scan a number +switch (current) +{ +case '-': +{ +add(current); +goto scan_number_minus; +} + +case '0': +{ +add(current); +goto scan_number_zero; +} + +case '1': +case '2': +case '3': +case '4': +case '5': +case '6': +case '7': +case '8': +case '9': +{ +add(current); +goto scan_number_any1; +} + +default: +{ +// all other characters are rejected outside scan_number() +assert(false); // LCOV_EXCL_LINE +} +} + +scan_number_minus: +// state: we just parsed a leading minus sign +number_type = token_type::value_integer; +switch (get()) +{ +case '0': +{ +add(current); +goto scan_number_zero; +} + +case '1': +case '2': +case '3': +case '4': +case '5': +case '6': +case '7': +case '8': +case '9': +{ +add(current); +goto scan_number_any1; +} + +default: +{ +error_message = "invalid number; expected digit after '-'"; +return token_type::parse_error; +} +} + +scan_number_zero: +// state: we just parse a zero (maybe with a leading minus sign) +switch (get()) +{ +case '.': +{ +add(decimal_point_char); +goto scan_number_decimal1; +} + +case 'e': +case 'E': +{ +add(current); +goto scan_number_exponent; +} + +default: +goto scan_number_done; +} + +scan_number_any1: +// state: we just parsed a number 0-9 (maybe with a leading minus sign) +switch (get()) +{ +case '0': +case '1': +case '2': +case '3': +case '4': +case '5': +case '6': +case '7': +case '8': +case '9': +{ +add(current); +goto scan_number_any1; +} + +case '.': +{ +add(decimal_point_char); +goto scan_number_decimal1; +} + +case 'e': +case 'E': +{ +add(current); +goto scan_number_exponent; +} + +default: +goto scan_number_done; +} + +scan_number_decimal1: +// state: we just parsed a decimal point +number_type = token_type::value_float; +switch (get()) +{ +case '0': +case '1': +case '2': +case '3': +case '4': +case '5': +case '6': +case '7': +case '8': +case '9': +{ +add(current); +goto scan_number_decimal2; +} + +default: +{ +error_message = "invalid number; expected digit after '.'"; +return token_type::parse_error; +} +} + +scan_number_decimal2: +// we just parsed at least one number after a decimal point +switch (get()) +{ +case '0': +case '1': +case '2': +case '3': +case '4': +case '5': +case '6': +case '7': +case '8': +case '9': +{ +add(current); +goto scan_number_decimal2; +} + +case 'e': +case 'E': +{ +add(current); +goto scan_number_exponent; +} + +default: +goto scan_number_done; +} + +scan_number_exponent: +// we just parsed an exponent +number_type = token_type::value_float; +switch (get()) +{ +case '+': +case '-': +{ +add(current); +goto scan_number_sign; +} + +case '0': +case '1': +case '2': +case '3': +case '4': +case '5': +case '6': +case '7': +case '8': +case '9': +{ +add(current); +goto scan_number_any2; +} + +default: +{ +error_message = +"invalid number; expected '+', '-', or digit after exponent"; +return token_type::parse_error; +} +} + +scan_number_sign: +// we just parsed an exponent sign +switch (get()) +{ +case '0': +case '1': +case '2': +case '3': +case '4': +case '5': +case '6': +case '7': +case '8': +case '9': +{ +add(current); +goto scan_number_any2; +} + +default: +{ +error_message = "invalid number; expected digit after exponent sign"; +return token_type::parse_error; +} +} + +scan_number_any2: +// we just parsed a number after the exponent or exponent sign +switch (get()) +{ +case '0': +case '1': +case '2': +case '3': +case '4': +case '5': +case '6': +case '7': +case '8': +case '9': +{ +add(current); +goto scan_number_any2; +} + +default: +goto scan_number_done; +} + +scan_number_done: +// unget the character after the number (we only read it to know that +// we are done scanning a number) +unget(); + +char* endptr = nullptr; +errno = 0; + +// try to parse integers first and fall back to floats +if (number_type == token_type::value_unsigned) +{ +const auto x = std::strtoull(token_buffer.data(), &endptr, 10); + +// we checked the number format before +assert(endptr == token_buffer.data() + token_buffer.size()); + +if (errno == 0) +{ +value_unsigned = static_cast(x); +if (value_unsigned == x) +{ +return token_type::value_unsigned; +} +} +} +else if (number_type == token_type::value_integer) +{ +const auto x = std::strtoll(token_buffer.data(), &endptr, 10); + +// we checked the number format before +assert(endptr == token_buffer.data() + token_buffer.size()); + +if (errno == 0) +{ +value_integer = static_cast(x); +if (value_integer == x) +{ +return token_type::value_integer; +} +} +} + +// this code is reached if we parse a floating-point number or if an +// integer conversion above failed +strtof(value_float, token_buffer.data(), &endptr); + +// we checked the number format before +assert(endptr == token_buffer.data() + token_buffer.size()); + +return token_type::value_float; +} + +/*! + @param[in] literal_text the literal text to expect + @param[in] length the length of the passed literal text + @param[in] return_type the token type to return on success + */ +token_type scan_literal(const char* literal_text, const std::size_t length, +token_type return_type) +{ +assert(current == literal_text[0]); +for (std::size_t i = 1; i < length; ++i) +{ +if (JSON_UNLIKELY(get() != literal_text[i])) +{ +error_message = "invalid literal"; +return token_type::parse_error; +} +} +return return_type; +} + +///////////////////// +// input management +///////////////////// + +/// reset token_buffer; current character is beginning of token +void reset() noexcept +{ +token_buffer.clear(); +token_string.clear(); +token_string.push_back(std::char_traits::to_char_type(current)); +} + +/* + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a + `std::char_traits::eof()` in that case. Stores the scanned characters + for use in error messages. + + @return character read from the input + */ +std::char_traits::int_type get() +{ +++chars_read; +current = ia->get_character(); +if (JSON_LIKELY(current != std::char_traits::eof())) +{ +token_string.push_back(std::char_traits::to_char_type(current)); +} +return current; +} + +/// unget current character (return it again on next get) +void unget() +{ +--chars_read; +if (JSON_LIKELY(current != std::char_traits::eof())) +{ +ia->unget_character(); +assert(token_string.size() != 0); +token_string.pop_back(); +} +} + +/// add a character to token_buffer +void add(int c) +{ +token_buffer.push_back(std::char_traits::to_char_type(c)); +} + +public: +///////////////////// +// value getters +///////////////////// + +/// return integer value +constexpr number_integer_t get_number_integer() const noexcept +{ +return value_integer; +} + +/// return unsigned integer value +constexpr number_unsigned_t get_number_unsigned() const noexcept +{ +return value_unsigned; +} + +/// return floating-point value +constexpr number_float_t get_number_float() const noexcept +{ +return value_float; +} + +/// return current string value (implicitly resets the token; useful only once) +std::string move_string() +{ +return std::move(token_buffer); +} + +///////////////////// +// diagnostics +///////////////////// + +/// return position of last read token +constexpr std::size_t get_position() const noexcept +{ +return chars_read; +} + +/// return the last read token (for errors only). Will never contain EOF +/// (an arbitrary value that is not a valid char value, often -1), because +/// 255 may legitimately occur. May contain NUL, which should be escaped. +std::string get_token_string() const +{ +// escape control characters +std::string result; +for (const auto c : token_string) +{ +if ('\x00' <= c and c <= '\x1F') +{ +// escape control characters +std::stringstream ss; +ss << "(c) << ">"; +result += ss.str(); +} +else +{ +// add character as is +result.push_back(c); +} +} + +return result; +} + +/// return syntax error message +constexpr const char* get_error_message() const noexcept +{ +return error_message; +} + +///////////////////// +// actual scanner +///////////////////// + +token_type scan() +{ +// read next character and ignore whitespace +do +{ +get(); +} +while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); + +switch (current) +{ +// structural characters +case '[': +return token_type::begin_array; +case ']': +return token_type::end_array; +case '{': +return token_type::begin_object; +case '}': +return token_type::end_object; +case ':': +return token_type::name_separator; +case ',': +return token_type::value_separator; + +// literals +case 't': +return scan_literal("true", 4, token_type::literal_true); +case 'f': +return scan_literal("false", 5, token_type::literal_false); +case 'n': +return scan_literal("null", 4, token_type::literal_null); + +// string +case '\"': +return scan_string(); + +// number +case '-': +case '0': +case '1': +case '2': +case '3': +case '4': +case '5': +case '6': +case '7': +case '8': +case '9': +return scan_number(); + +// end of input (the null byte is needed when parsing from +// string literals) +case '\0': +case std::char_traits::eof(): +return token_type::end_of_input; + +// error +default: +error_message = "invalid literal"; +return token_type::parse_error; +} +} + +private: +/// input adapter +detail::input_adapter_t ia = nullptr; + +/// the current character +std::char_traits::int_type current = std::char_traits::eof(); + +/// the number of characters read +std::size_t chars_read = 0; + +/// raw input token string (for error messages) +std::vector token_string {}; + +/// buffer for variable-length tokens (numbers, strings) +std::string token_buffer {}; + +/// a description of occurred lexer errors +const char* error_message = ""; + +// number values +number_integer_t value_integer = 0; +number_unsigned_t value_unsigned = 0; +number_float_t value_float = 0; + +/// the decimal point +const char decimal_point_char = '.'; +}; +} +} + +// #include + + +#include // assert +#include // isfinite +#include // uint8_t +#include // function +#include // string +#include // move + +// #include + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +//////////// +// parser // +//////////// + +/*! +@brief syntax analysis + +This class implements a recursive decent parser. +*/ +template +class parser +{ +using number_integer_t = typename BasicJsonType::number_integer_t; +using number_unsigned_t = typename BasicJsonType::number_unsigned_t; +using number_float_t = typename BasicJsonType::number_float_t; +using lexer_t = lexer; +using token_type = typename lexer_t::token_type; + +public: +enum class parse_event_t : uint8_t +{ +/// the parser read `{` and started to process a JSON object +object_start, +/// the parser read `}` and finished processing a JSON object +object_end, +/// the parser read `[` and started to process a JSON array +array_start, +/// the parser read `]` and finished processing a JSON array +array_end, +/// the parser read a key of a value in an object +key, +/// the parser finished reading a JSON value +value +}; + +using parser_callback_t = +std::function; + +/// a parser reading from an input adapter +explicit parser(detail::input_adapter_t adapter, +const parser_callback_t cb = nullptr, +const bool allow_exceptions_ = true) +: callback(cb), m_lexer(adapter), allow_exceptions(allow_exceptions_) +{} + +/*! + @brief public parser interface + + @param[in] strict whether to expect the last token to be EOF + @param[in,out] result parsed JSON value + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ +void parse(const bool strict, BasicJsonType& result) +{ +// read first token +get_token(); + +parse_internal(true, result); +result.assert_invariant(); + +// in strict mode, input must be completely read +if (strict) +{ +get_token(); +expect(token_type::end_of_input); +} + +// in case of an error, return discarded value +if (errored) +{ +result = value_t::discarded; +return; +} + +// set top-level value to null if it was discarded by the callback +// function +if (result.is_discarded()) +{ +result = nullptr; +} +} + +/*! + @brief public accept interface + + @param[in] strict whether to expect the last token to be EOF + @return whether the input is a proper JSON text + */ +bool accept(const bool strict = true) +{ +// read first token +get_token(); + +if (not accept_internal()) +{ +return false; +} + +// strict => last token must be EOF +return not strict or (get_token() == token_type::end_of_input); +} + +private: +/*! + @brief the actual parser + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ +void parse_internal(bool keep, BasicJsonType& result) +{ +// never parse after a parse error was detected +assert(not errored); + +// start with a discarded value +if (not result.is_discarded()) +{ +result.m_value.destroy(result.m_type); +result.m_type = value_t::discarded; +} + +switch (last_token) +{ +case token_type::begin_object: +{ +if (keep) +{ +if (callback) +{ +keep = callback(depth++, parse_event_t::object_start, result); +} + +if (not callback or keep) +{ +// explicitly set result to object to cope with {} +result.m_type = value_t::object; +result.m_value = value_t::object; +} +} + +// read next token +get_token(); + +// closing } -> we are done +if (last_token == token_type::end_object) +{ +if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) +{ +result.m_value.destroy(result.m_type); +result.m_type = value_t::discarded; +} +break; +} + +// parse values +std::string key; +BasicJsonType value; +while (true) +{ +// store key +if (not expect(token_type::value_string)) +{ +return; +} +key = m_lexer.move_string(); + +bool keep_tag = false; +if (keep) +{ +if (callback) +{ +BasicJsonType k(key); +keep_tag = callback(depth, parse_event_t::key, k); +} +else +{ +keep_tag = true; +} +} + +// parse separator (:) +get_token(); +if (not expect(token_type::name_separator)) +{ +return; +} + +// parse and add value +get_token(); +value.m_value.destroy(value.m_type); +value.m_type = value_t::discarded; +parse_internal(keep, value); + +if (JSON_UNLIKELY(errored)) +{ +return; +} + +if (keep and keep_tag and not value.is_discarded()) +{ +result.m_value.object->emplace(std::move(key), std::move(value)); +} + +// comma -> next value +get_token(); +if (last_token == token_type::value_separator) +{ +get_token(); +continue; +} + +// closing } +if (not expect(token_type::end_object)) +{ +return; +} +break; +} + +if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) +{ +result.m_value.destroy(result.m_type); +result.m_type = value_t::discarded; +} +break; +} + +case token_type::begin_array: +{ +if (keep) +{ +if (callback) +{ +keep = callback(depth++, parse_event_t::array_start, result); +} + +if (not callback or keep) +{ +// explicitly set result to array to cope with [] +result.m_type = value_t::array; +result.m_value = value_t::array; +} +} + +// read next token +get_token(); + +// closing ] -> we are done +if (last_token == token_type::end_array) +{ +if (callback and not callback(--depth, parse_event_t::array_end, result)) +{ +result.m_value.destroy(result.m_type); +result.m_type = value_t::discarded; +} +break; +} + +// parse values +BasicJsonType value; +while (true) +{ +// parse value +value.m_value.destroy(value.m_type); +value.m_type = value_t::discarded; +parse_internal(keep, value); + +if (JSON_UNLIKELY(errored)) +{ +return; +} + +if (keep and not value.is_discarded()) +{ +result.m_value.array->push_back(std::move(value)); +} + +// comma -> next value +get_token(); +if (last_token == token_type::value_separator) +{ +get_token(); +continue; +} + +// closing ] +if (not expect(token_type::end_array)) +{ +return; +} +break; +} + +if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) +{ +result.m_value.destroy(result.m_type); +result.m_type = value_t::discarded; +} +break; +} + +case token_type::literal_null: +{ +result.m_type = value_t::null; +break; +} + +case token_type::value_string: +{ +result.m_type = value_t::string; +result.m_value = m_lexer.move_string(); +break; +} + +case token_type::literal_true: +{ +result.m_type = value_t::boolean; +result.m_value = true; +break; +} + +case token_type::literal_false: +{ +result.m_type = value_t::boolean; +result.m_value = false; +break; +} + +case token_type::value_unsigned: +{ +result.m_type = value_t::number_unsigned; +result.m_value = m_lexer.get_number_unsigned(); +break; +} + +case token_type::value_integer: +{ +result.m_type = value_t::number_integer; +result.m_value = m_lexer.get_number_integer(); +break; +} + +case token_type::value_float: +{ +result.m_type = value_t::number_float; +result.m_value = m_lexer.get_number_float(); + +// throw in case of infinity or NAN +if (JSON_UNLIKELY(not std::isfinite(result.m_value.number_float))) +{ +if (allow_exceptions) +{ +JSON_THROW(out_of_range::create(406, "number overflow parsing '" + +m_lexer.get_token_string() + "'")); +} +expect(token_type::uninitialized); +} +break; +} + +case token_type::parse_error: +{ +// using "uninitialized" to avoid "expected" message +if (not expect(token_type::uninitialized)) +{ +return; +} +break; // LCOV_EXCL_LINE +} + +default: +{ +// the last token was unexpected; we expected a value +if (not expect(token_type::literal_or_value)) +{ +return; +} +break; // LCOV_EXCL_LINE +} +} + +if (keep and callback and not callback(depth, parse_event_t::value, result)) +{ +result.m_type = value_t::discarded; +} +} + +/*! + @brief the actual acceptor + + @invariant 1. The last token is not yet processed. Therefore, the caller + of this function must make sure a token has been read. + 2. When this function returns, the last token is processed. + That is, the last read character was already considered. + + This invariant makes sure that no token needs to be "unput". + */ +bool accept_internal() +{ +switch (last_token) +{ +case token_type::begin_object: +{ +// read next token +get_token(); + +// closing } -> we are done +if (last_token == token_type::end_object) +{ +return true; +} + +// parse values +while (true) +{ +// parse key +if (last_token != token_type::value_string) +{ +return false; +} + +// parse separator (:) +get_token(); +if (last_token != token_type::name_separator) +{ +return false; +} + +// parse value +get_token(); +if (not accept_internal()) +{ +return false; +} + +// comma -> next value +get_token(); +if (last_token == token_type::value_separator) +{ +get_token(); +continue; +} + +// closing } +return (last_token == token_type::end_object); +} +} + +case token_type::begin_array: +{ +// read next token +get_token(); + +// closing ] -> we are done +if (last_token == token_type::end_array) +{ +return true; +} + +// parse values +while (true) +{ +// parse value +if (not accept_internal()) +{ +return false; +} + +// comma -> next value +get_token(); +if (last_token == token_type::value_separator) +{ +get_token(); +continue; +} + +// closing ] +return (last_token == token_type::end_array); +} +} + +case token_type::value_float: +{ +// reject infinity or NAN +return std::isfinite(m_lexer.get_number_float()); +} + +case token_type::literal_false: +case token_type::literal_null: +case token_type::literal_true: +case token_type::value_integer: +case token_type::value_string: +case token_type::value_unsigned: +return true; + +default: // the last token was unexpected +return false; +} +} + +/// get next token from lexer +token_type get_token() +{ +return (last_token = m_lexer.scan()); +} + +/*! + @throw parse_error.101 if expected token did not occur + */ +bool expect(token_type t) +{ +if (JSON_UNLIKELY(t != last_token)) +{ +errored = true; +expected = t; +if (allow_exceptions) +{ +throw_exception(); +} +else +{ +return false; +} +} + +return true; +} + +[[noreturn]] void throw_exception() const +{ +std::string error_msg = "syntax error - "; +if (last_token == token_type::parse_error) +{ +error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" + +m_lexer.get_token_string() + "'"; +} +else +{ +error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token)); +} + +if (expected != token_type::uninitialized) +{ +error_msg += "; expected " + std::string(lexer_t::token_type_name(expected)); +} + +JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg)); +} + +private: +/// current level of recursion +int depth = 0; +/// callback function +const parser_callback_t callback = nullptr; +/// the type of the last read token +token_type last_token = token_type::uninitialized; +/// the lexer +lexer_t m_lexer; +/// whether a syntax error occurred +bool errored = false; +/// possible reason for the syntax error +token_type expected = token_type::uninitialized; +/// whether to throw exceptions in case of errors +const bool allow_exceptions = true; +}; +} +} + +// #include + + +#include // ptrdiff_t +#include // numeric_limits + +namespace nlohmann +{ +namespace detail +{ +/* +@brief an iterator for primitive JSON types + +This class models an iterator for primitive JSON types (boolean, number, +string). It's only purpose is to allow the iterator/const_iterator classes +to "iterate" over primitive values. Internally, the iterator is modeled by +a `difference_type` variable. Value begin_value (`0`) models the begin, +end_value (`1`) models past the end. +*/ +class primitive_iterator_t +{ +private: +using difference_type = std::ptrdiff_t; +static constexpr difference_type begin_value = 0; +static constexpr difference_type end_value = begin_value + 1; + +/// iterator as signed integer type +difference_type m_it = (std::numeric_limits::min)(); + +public: +constexpr difference_type get_value() const noexcept +{ +return m_it; +} + +/// set iterator to a defined beginning +void set_begin() noexcept +{ +m_it = begin_value; +} + +/// set iterator to a defined past the end +void set_end() noexcept +{ +m_it = end_value; +} + +/// return whether the iterator can be dereferenced +constexpr bool is_begin() const noexcept +{ +return m_it == begin_value; +} + +/// return whether the iterator is at end +constexpr bool is_end() const noexcept +{ +return m_it == end_value; +} + +friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept +{ +return lhs.m_it == rhs.m_it; +} + +friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept +{ +return lhs.m_it < rhs.m_it; +} + +primitive_iterator_t operator+(difference_type n) noexcept +{ +auto result = *this; +result += n; +return result; +} + +friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept +{ +return lhs.m_it - rhs.m_it; +} + +primitive_iterator_t& operator++() noexcept +{ +++m_it; +return *this; +} + +primitive_iterator_t const operator++(int) noexcept +{ +auto result = *this; +m_it++; +return result; +} + +primitive_iterator_t& operator--() noexcept +{ +--m_it; +return *this; +} + +primitive_iterator_t const operator--(int) noexcept +{ +auto result = *this; +m_it--; +return result; +} + +primitive_iterator_t& operator+=(difference_type n) noexcept +{ +m_it += n; +return *this; +} + +primitive_iterator_t& operator-=(difference_type n) noexcept +{ +m_it -= n; +return *this; +} +}; +} +} + +// #include + + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/*! +@brief an iterator value + +@note This structure could easily be a union, but MSVC currently does not allow +unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. +*/ +template struct internal_iterator +{ +/// iterator for JSON objects +typename BasicJsonType::object_t::iterator object_iterator {}; +/// iterator for JSON arrays +typename BasicJsonType::array_t::iterator array_iterator {}; +/// generic iterator for all other types +primitive_iterator_t primitive_iterator {}; +}; +} +} + +// #include + + +#include // not +#include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next +#include // conditional, is_const, remove_const + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +// forward declare, to be able to friend it later on +template class iteration_proxy; + +/*! +@brief a template for a bidirectional iterator for the @ref basic_json class + +This class implements a both iterators (iterator and const_iterator) for the +@ref basic_json class. + +@note An iterator is called *initialized* when a pointer to a JSON value has + been set (e.g., by a constructor or a copy assignment). If the iterator is + default-constructed, it is *uninitialized* and most methods are undefined. + **The library uses assertions to detect calls on uninitialized iterators.** + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). + +@since version 1.0.0, simplified in version 2.0.9, change to bidirectional + iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) +*/ +template +class iter_impl +{ +/// allow basic_json to access private members +friend iter_impl::value, typename std::remove_const::type, const BasicJsonType>::type>; +friend BasicJsonType; +friend iteration_proxy; + +using object_t = typename BasicJsonType::object_t; +using array_t = typename BasicJsonType::array_t; +// make sure BasicJsonType is basic_json or const basic_json +static_assert(is_basic_json::type>::value, +"iter_impl only accepts (const) basic_json"); + +public: + +/// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. +/// The C++ Standard has never required user-defined iterators to derive from std::iterator. +/// A user-defined iterator should provide publicly accessible typedefs named +/// iterator_category, value_type, difference_type, pointer, and reference. +/// Note that value_type is required to be non-const, even for constant iterators. +using iterator_category = std::bidirectional_iterator_tag; + +/// the type of the values when the iterator is dereferenced +using value_type = typename BasicJsonType::value_type; +/// a type to represent differences between iterators +using difference_type = typename BasicJsonType::difference_type; +/// defines a pointer to the type iterated over (value_type) +using pointer = typename std::conditional::value, +typename BasicJsonType::const_pointer, +typename BasicJsonType::pointer>::type; +/// defines a reference to the type iterated over (value_type) +using reference = +typename std::conditional::value, +typename BasicJsonType::const_reference, +typename BasicJsonType::reference>::type; + +/// default constructor +iter_impl() = default; + +/*! + @brief constructor for a given JSON instance + @param[in] object pointer to a JSON object for this iterator + @pre object != nullptr + @post The iterator is initialized; i.e. `m_object != nullptr`. + */ +explicit iter_impl(pointer object) noexcept : m_object(object) +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +{ +m_it.object_iterator = typename object_t::iterator(); +break; +} + +case value_t::array: +{ +m_it.array_iterator = typename array_t::iterator(); +break; +} + +default: +{ +m_it.primitive_iterator = primitive_iterator_t(); +break; +} +} +} + +/*! + @note The conventional copy constructor and copy assignment are implicitly + defined. Combined with the following converting constructor and + assignment, they support: (1) copy from iterator to iterator, (2) + copy from const iterator to const iterator, and (3) conversion from + iterator to const iterator. However conversion from const iterator + to iterator is not defined. + */ + +/*! + @brief converting constructor + @param[in] other non-const iterator to copy from + @note It is not checked whether @a other is initialized. + */ +iter_impl(const iter_impl::type>& other) noexcept +: m_object(other.m_object), m_it(other.m_it) {} + +/*! + @brief converting assignment + @param[in,out] other non-const iterator to copy from + @return const/non-const iterator + @note It is not checked whether @a other is initialized. + */ +iter_impl& operator=(const iter_impl::type>& other) noexcept +{ +m_object = other.m_object; +m_it = other.m_it; +return *this; +} + +private: +/*! + @brief set the iterator to the first value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +void set_begin() noexcept +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +{ +m_it.object_iterator = m_object->m_value.object->begin(); +break; +} + +case value_t::array: +{ +m_it.array_iterator = m_object->m_value.array->begin(); +break; +} + +case value_t::null: +{ +// set to end so begin()==end() is true: null is empty +m_it.primitive_iterator.set_end(); +break; +} + +default: +{ +m_it.primitive_iterator.set_begin(); +break; +} +} +} + +/*! + @brief set the iterator past the last value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +void set_end() noexcept +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +{ +m_it.object_iterator = m_object->m_value.object->end(); +break; +} + +case value_t::array: +{ +m_it.array_iterator = m_object->m_value.array->end(); +break; +} + +default: +{ +m_it.primitive_iterator.set_end(); +break; +} +} +} + +public: +/*! + @brief return a reference to the value pointed to by the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +reference operator*() const +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +{ +assert(m_it.object_iterator != m_object->m_value.object->end()); +return m_it.object_iterator->second; +} + +case value_t::array: +{ +assert(m_it.array_iterator != m_object->m_value.array->end()); +return *m_it.array_iterator; +} + +case value_t::null: +JSON_THROW(invalid_iterator::create(214, "cannot get value")); + +default: +{ +if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) +{ +return *m_object; +} + +JSON_THROW(invalid_iterator::create(214, "cannot get value")); +} +} +} + +/*! + @brief dereference the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +pointer operator->() const +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +{ +assert(m_it.object_iterator != m_object->m_value.object->end()); +return &(m_it.object_iterator->second); +} + +case value_t::array: +{ +assert(m_it.array_iterator != m_object->m_value.array->end()); +return &*m_it.array_iterator; +} + +default: +{ +if (JSON_LIKELY(m_it.primitive_iterator.is_begin())) +{ +return m_object; +} + +JSON_THROW(invalid_iterator::create(214, "cannot get value")); +} +} +} + +/*! + @brief post-increment (it++) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +iter_impl const operator++(int) +{ +auto result = *this; +++(*this); +return result; +} + +/*! + @brief pre-increment (++it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +iter_impl& operator++() +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +{ +std::advance(m_it.object_iterator, 1); +break; +} + +case value_t::array: +{ +std::advance(m_it.array_iterator, 1); +break; +} + +default: +{ +++m_it.primitive_iterator; +break; +} +} + +return *this; +} + +/*! + @brief post-decrement (it--) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +iter_impl const operator--(int) +{ +auto result = *this; +--(*this); +return result; +} + +/*! + @brief pre-decrement (--it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +iter_impl& operator--() +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +{ +std::advance(m_it.object_iterator, -1); +break; +} + +case value_t::array: +{ +std::advance(m_it.array_iterator, -1); +break; +} + +default: +{ +--m_it.primitive_iterator; +break; +} +} + +return *this; +} + +/*! + @brief comparison: equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +bool operator==(const iter_impl& other) const +{ +// if objects are not the same, the comparison is undefined +if (JSON_UNLIKELY(m_object != other.m_object)) +{ +JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); +} + +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +return (m_it.object_iterator == other.m_it.object_iterator); + +case value_t::array: +return (m_it.array_iterator == other.m_it.array_iterator); + +default: +return (m_it.primitive_iterator == other.m_it.primitive_iterator); +} +} + +/*! + @brief comparison: not equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +bool operator!=(const iter_impl& other) const +{ +return not operator==(other); +} + +/*! + @brief comparison: smaller + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +bool operator<(const iter_impl& other) const +{ +// if objects are not the same, the comparison is undefined +if (JSON_UNLIKELY(m_object != other.m_object)) +{ +JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); +} + +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators")); + +case value_t::array: +return (m_it.array_iterator < other.m_it.array_iterator); + +default: +return (m_it.primitive_iterator < other.m_it.primitive_iterator); +} +} + +/*! + @brief comparison: less than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +bool operator<=(const iter_impl& other) const +{ +return not other.operator < (*this); +} + +/*! + @brief comparison: greater than + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +bool operator>(const iter_impl& other) const +{ +return not operator<=(other); +} + +/*! + @brief comparison: greater than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +bool operator>=(const iter_impl& other) const +{ +return not operator<(other); +} + +/*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +iter_impl& operator+=(difference_type i) +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + +case value_t::array: +{ +std::advance(m_it.array_iterator, i); +break; +} + +default: +{ +m_it.primitive_iterator += i; +break; +} +} + +return *this; +} + +/*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +iter_impl& operator-=(difference_type i) +{ +return operator+=(-i); +} + +/*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +iter_impl operator+(difference_type i) const +{ +auto result = *this; +result += i; +return result; +} + +/*! + @brief addition of distance and iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +friend iter_impl operator+(difference_type i, const iter_impl& it) +{ +auto result = it; +result += i; +return result; +} + +/*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +iter_impl operator-(difference_type i) const +{ +auto result = *this; +result -= i; +return result; +} + +/*! + @brief return difference + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +difference_type operator-(const iter_impl& other) const +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + +case value_t::array: +return m_it.array_iterator - other.m_it.array_iterator; + +default: +return m_it.primitive_iterator - other.m_it.primitive_iterator; +} +} + +/*! + @brief access to successor + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +reference operator[](difference_type n) const +{ +assert(m_object != nullptr); + +switch (m_object->m_type) +{ +case value_t::object: +JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators")); + +case value_t::array: +return *std::next(m_it.array_iterator, n); + +case value_t::null: +JSON_THROW(invalid_iterator::create(214, "cannot get value")); + +default: +{ +if (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n)) +{ +return *m_object; +} + +JSON_THROW(invalid_iterator::create(214, "cannot get value")); +} +} +} + +/*! + @brief return the key of an object iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +typename object_t::key_type key() const +{ +assert(m_object != nullptr); + +if (JSON_LIKELY(m_object->is_object())) +{ +return m_it.object_iterator->first; +} + +JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators")); +} + +/*! + @brief return the value of an iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ +reference value() const +{ +return operator*(); +} + +private: +/// associated JSON instance +pointer m_object = nullptr; +/// the actual iterator of the associated instance +internal_iterator::type> m_it; +}; +} +} + +// #include + + +#include // size_t +#include // string, to_string + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/// proxy class for the items() function +template class iteration_proxy +{ +private: +/// helper class for iteration +class iteration_proxy_internal +{ +private: +/// the iterator +IteratorType anchor; +/// an index for arrays (used to create key names) +std::size_t array_index = 0; + +public: +explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} + +/// dereference operator (needed for range-based for) +iteration_proxy_internal& operator*() +{ +return *this; +} + +/// increment operator (needed for range-based for) +iteration_proxy_internal& operator++() +{ +++anchor; +++array_index; + +return *this; +} + +/// inequality operator (needed for range-based for) +bool operator!=(const iteration_proxy_internal& o) const noexcept +{ +return anchor != o.anchor; +} + +/// return key of the iterator +std::string key() const +{ +assert(anchor.m_object != nullptr); + +switch (anchor.m_object->type()) +{ +// use integer array index as key +case value_t::array: +return std::to_string(array_index); + +// use key from the object +case value_t::object: +return anchor.key(); + +// use an empty key for all primitive types +default: +return ""; +} +} + +/// return value of the iterator +typename IteratorType::reference value() const +{ +return anchor.value(); +} +}; + +/// the container to iterate +typename IteratorType::reference container; + +public: +/// construct iteration proxy from a container +explicit iteration_proxy(typename IteratorType::reference cont) noexcept +: container(cont) {} + +/// return iterator begin (needed for range-based for) +iteration_proxy_internal begin() noexcept +{ +return iteration_proxy_internal(container.begin()); +} + +/// return iterator end (needed for range-based for) +iteration_proxy_internal end() noexcept +{ +return iteration_proxy_internal(container.end()); +} +}; +} +} + +// #include + + +#include // ptrdiff_t +#include // reverse_iterator +#include // declval + +namespace nlohmann +{ +namespace detail +{ +////////////////////// +// reverse_iterator // +////////////////////// + +/*! +@brief a template for a reverse iterator class + +@tparam Base the base iterator type to reverse. Valid types are @ref +iterator (to create @ref reverse_iterator) and @ref const_iterator (to +create @ref const_reverse_iterator). + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). +- [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): + It is possible to write to the pointed-to element (only if @a Base is + @ref iterator). + +@since version 1.0.0 +*/ +template +class json_reverse_iterator : public std::reverse_iterator +{ +public: +using difference_type = std::ptrdiff_t; +/// shortcut to the reverse iterator adapter +using base_iterator = std::reverse_iterator; +/// the reference type for the pointed-to element +using reference = typename Base::reference; + +/// create reverse iterator from iterator +json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept +: base_iterator(it) {} + +/// create reverse iterator from base class +json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} + +/// post-increment (it++) +json_reverse_iterator const operator++(int) +{ +return static_cast(base_iterator::operator++(1)); +} + +/// pre-increment (++it) +json_reverse_iterator& operator++() +{ +return static_cast(base_iterator::operator++()); +} + +/// post-decrement (it--) +json_reverse_iterator const operator--(int) +{ +return static_cast(base_iterator::operator--(1)); +} + +/// pre-decrement (--it) +json_reverse_iterator& operator--() +{ +return static_cast(base_iterator::operator--()); +} + +/// add to iterator +json_reverse_iterator& operator+=(difference_type i) +{ +return static_cast(base_iterator::operator+=(i)); +} + +/// add to iterator +json_reverse_iterator operator+(difference_type i) const +{ +return static_cast(base_iterator::operator+(i)); +} + +/// subtract from iterator +json_reverse_iterator operator-(difference_type i) const +{ +return static_cast(base_iterator::operator-(i)); +} + +/// return difference +difference_type operator-(const json_reverse_iterator& other) const +{ +return base_iterator(*this) - base_iterator(other); +} + +/// access to successor +reference operator[](difference_type n) const +{ +return *(this->operator+(n)); +} + +/// return the key of an object iterator +auto key() const -> decltype(std::declval().key()) +{ +auto it = --this->base(); +return it.key(); +} + +/// return the value of an iterator +reference value() const +{ +auto it = --this->base(); +return it.operator * (); +} +}; +} +} + +// #include + + +#include // copy +#include // size_t +#include // streamsize +#include // back_inserter +#include // shared_ptr, make_shared +#include // basic_ostream +#include // basic_string +#include // vector + +namespace nlohmann +{ +namespace detail +{ +/// abstract output adapter interface +template struct output_adapter_protocol +{ +virtual void write_character(CharType c) = 0; +virtual void write_characters(const CharType* s, std::size_t length) = 0; +virtual ~output_adapter_protocol() = default; +}; + +/// a type to simplify interfaces +template +using output_adapter_t = std::shared_ptr>; + +/// output adapter for byte vectors +template +class output_vector_adapter : public output_adapter_protocol +{ +public: +explicit output_vector_adapter(std::vector& vec) : v(vec) {} + +void write_character(CharType c) override +{ +v.push_back(c); +} + +void write_characters(const CharType* s, std::size_t length) override +{ +std::copy(s, s + length, std::back_inserter(v)); +} + +private: +std::vector& v; +}; + +/// output adapter for output streams +template +class output_stream_adapter : public output_adapter_protocol +{ +public: +explicit output_stream_adapter(std::basic_ostream& s) : stream(s) {} + +void write_character(CharType c) override +{ +stream.put(c); +} + +void write_characters(const CharType* s, std::size_t length) override +{ +stream.write(s, static_cast(length)); +} + +private: +std::basic_ostream& stream; +}; + +/// output adapter for basic_string +template +class output_string_adapter : public output_adapter_protocol +{ +public: +explicit output_string_adapter(std::basic_string& s) : str(s) {} + +void write_character(CharType c) override +{ +str.push_back(c); +} + +void write_characters(const CharType* s, std::size_t length) override +{ +str.append(s, length); +} + +private: +std::basic_string& str; +}; + +template +class output_adapter +{ +public: +output_adapter(std::vector& vec) +: oa(std::make_shared>(vec)) {} + +output_adapter(std::basic_ostream& s) +: oa(std::make_shared>(s)) {} + +output_adapter(std::basic_string& s) +: oa(std::make_shared>(s)) {} + +operator output_adapter_t() +{ +return oa; +} + +private: +output_adapter_t oa = nullptr; +}; +} +} + +// #include + + +#include // generate_n +#include // array +#include // assert +#include // ldexp +#include // size_t +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // setw, setfill +#include // hex +#include // back_inserter +#include // numeric_limits +#include // stringstream +#include // char_traits, string +#include // make_pair, move + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// binary reader // +/////////////////// + +/*! +@brief deserialization of CBOR and MessagePack values +*/ +template +class binary_reader +{ +using number_integer_t = typename BasicJsonType::number_integer_t; +using number_unsigned_t = typename BasicJsonType::number_unsigned_t; +using string_t = typename BasicJsonType::string_t; + +public: +/*! + @brief create a binary reader + + @param[in] adapter input adapter to read from + */ +explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter)) +{ +assert(ia); +} + +/*! + @brief create a JSON value from CBOR input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from CBOR input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ +BasicJsonType parse_cbor(const bool strict) +{ +const auto res = parse_cbor_internal(); +if (strict) +{ +get(); +expect_eof(); +} +return res; +} + +/*! + @brief create a JSON value from MessagePack input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from MessagePack input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ +BasicJsonType parse_msgpack(const bool strict) +{ +const auto res = parse_msgpack_internal(); +if (strict) +{ +get(); +expect_eof(); +} +return res; +} + +/*! + @brief create a JSON value from UBJSON input + + @param[in] strict whether to expect the input to be consumed completed + @return JSON value created from UBJSON input + + @throw parse_error.110 if input ended unexpectedly or the end of file was + not reached when @a strict was set to true + @throw parse_error.112 if unsupported byte was read + */ +BasicJsonType parse_ubjson(const bool strict) +{ +const auto res = parse_ubjson_internal(); +if (strict) +{ +get_ignore_noop(); +expect_eof(); +} +return res; +} + +/*! + @brief determine system byte order + + @return true if and only if system's byte order is little endian + + @note from http://stackoverflow.com/a/1001328/266378 + */ +static constexpr bool little_endianess(int num = 1) noexcept +{ +return (*reinterpret_cast(&num) == 1); +} + +private: +/*! + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + */ +BasicJsonType parse_cbor_internal(const bool get_char = true) +{ +switch (get_char ? get() : current) +{ +// EOF +case std::char_traits::eof(): +JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + +// Integer 0x00..0x17 (0..23) +case 0x00: +case 0x01: +case 0x02: +case 0x03: +case 0x04: +case 0x05: +case 0x06: +case 0x07: +case 0x08: +case 0x09: +case 0x0A: +case 0x0B: +case 0x0C: +case 0x0D: +case 0x0E: +case 0x0F: +case 0x10: +case 0x11: +case 0x12: +case 0x13: +case 0x14: +case 0x15: +case 0x16: +case 0x17: +return static_cast(current); + +case 0x18: // Unsigned integer (one-byte uint8_t follows) +return get_number(); + +case 0x19: // Unsigned integer (two-byte uint16_t follows) +return get_number(); + +case 0x1A: // Unsigned integer (four-byte uint32_t follows) +return get_number(); + +case 0x1B: // Unsigned integer (eight-byte uint64_t follows) +return get_number(); + +// Negative integer -1-0x00..-1-0x17 (-1..-24) +case 0x20: +case 0x21: +case 0x22: +case 0x23: +case 0x24: +case 0x25: +case 0x26: +case 0x27: +case 0x28: +case 0x29: +case 0x2A: +case 0x2B: +case 0x2C: +case 0x2D: +case 0x2E: +case 0x2F: +case 0x30: +case 0x31: +case 0x32: +case 0x33: +case 0x34: +case 0x35: +case 0x36: +case 0x37: +return static_cast(0x20 - 1 - current); + +case 0x38: // Negative integer (one-byte uint8_t follows) +{ +return static_cast(-1) - get_number(); +} + +case 0x39: // Negative integer -1-n (two-byte uint16_t follows) +{ +return static_cast(-1) - get_number(); +} + +case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) +{ +return static_cast(-1) - get_number(); +} + +case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) +{ +return static_cast(-1) - +static_cast(get_number()); +} + +// UTF-8 string (0x00..0x17 bytes follow) +case 0x60: +case 0x61: +case 0x62: +case 0x63: +case 0x64: +case 0x65: +case 0x66: +case 0x67: +case 0x68: +case 0x69: +case 0x6A: +case 0x6B: +case 0x6C: +case 0x6D: +case 0x6E: +case 0x6F: +case 0x70: +case 0x71: +case 0x72: +case 0x73: +case 0x74: +case 0x75: +case 0x76: +case 0x77: +case 0x78: // UTF-8 string (one-byte uint8_t for n follows) +case 0x79: // UTF-8 string (two-byte uint16_t for n follow) +case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) +case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) +case 0x7F: // UTF-8 string (indefinite length) +{ +return get_cbor_string(); +} + +// array (0x00..0x17 data items follow) +case 0x80: +case 0x81: +case 0x82: +case 0x83: +case 0x84: +case 0x85: +case 0x86: +case 0x87: +case 0x88: +case 0x89: +case 0x8A: +case 0x8B: +case 0x8C: +case 0x8D: +case 0x8E: +case 0x8F: +case 0x90: +case 0x91: +case 0x92: +case 0x93: +case 0x94: +case 0x95: +case 0x96: +case 0x97: +{ +return get_cbor_array(current & 0x1F); +} + +case 0x98: // array (one-byte uint8_t for n follows) +{ +return get_cbor_array(get_number()); +} + +case 0x99: // array (two-byte uint16_t for n follow) +{ +return get_cbor_array(get_number()); +} + +case 0x9A: // array (four-byte uint32_t for n follow) +{ +return get_cbor_array(get_number()); +} + +case 0x9B: // array (eight-byte uint64_t for n follow) +{ +return get_cbor_array(get_number()); +} + +case 0x9F: // array (indefinite length) +{ +BasicJsonType result = value_t::array; +while (get() != 0xFF) +{ +result.push_back(parse_cbor_internal(false)); +} +return result; +} + +// map (0x00..0x17 pairs of data items follow) +case 0xA0: +case 0xA1: +case 0xA2: +case 0xA3: +case 0xA4: +case 0xA5: +case 0xA6: +case 0xA7: +case 0xA8: +case 0xA9: +case 0xAA: +case 0xAB: +case 0xAC: +case 0xAD: +case 0xAE: +case 0xAF: +case 0xB0: +case 0xB1: +case 0xB2: +case 0xB3: +case 0xB4: +case 0xB5: +case 0xB6: +case 0xB7: +{ +return get_cbor_object(current & 0x1F); +} + +case 0xB8: // map (one-byte uint8_t for n follows) +{ +return get_cbor_object(get_number()); +} + +case 0xB9: // map (two-byte uint16_t for n follow) +{ +return get_cbor_object(get_number()); +} + +case 0xBA: // map (four-byte uint32_t for n follow) +{ +return get_cbor_object(get_number()); +} + +case 0xBB: // map (eight-byte uint64_t for n follow) +{ +return get_cbor_object(get_number()); +} + +case 0xBF: // map (indefinite length) +{ +BasicJsonType result = value_t::object; +while (get() != 0xFF) +{ +auto key = get_cbor_string(); +result[key] = parse_cbor_internal(); +} +return result; +} + +case 0xF4: // false +{ +return false; +} + +case 0xF5: // true +{ +return true; +} + +case 0xF6: // null +{ +return value_t::null; +} + +case 0xF9: // Half-Precision Float (two-byte IEEE 754) +{ +const int byte1 = get(); +unexpect_eof(); +const int byte2 = get(); +unexpect_eof(); + +// code from RFC 7049, Appendix D, Figure 3: +// As half-precision floating-point numbers were only added +// to IEEE 754 in 2008, today's programming platforms often +// still only have limited support for them. It is very +// easy to include at least decoding support for them even +// without such support. An example of a small decoder for +// half-precision floating-point numbers in the C language +// is shown in Fig. 3. +const int half = (byte1 << 8) + byte2; +const int exp = (half >> 10) & 0x1F; +const int mant = half & 0x3FF; +double val; +if (exp == 0) +{ +val = std::ldexp(mant, -24); +} +else if (exp != 31) +{ +val = std::ldexp(mant + 1024, exp - 25); +} +else +{ +val = (mant == 0) ? std::numeric_limits::infinity() +: std::numeric_limits::quiet_NaN(); +} +return (half & 0x8000) != 0 ? -val : val; +} + +case 0xFA: // Single-Precision Float (four-byte IEEE 754) +{ +return get_number(); +} + +case 0xFB: // Double-Precision Float (eight-byte IEEE 754) +{ +return get_number(); +} + +default: // anything else (0xFF is handled inside the other types) +{ +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; +JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + ss.str())); +} +} +} + +BasicJsonType parse_msgpack_internal() +{ +switch (get()) +{ +// EOF +case std::char_traits::eof(): +JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + +// positive fixint +case 0x00: +case 0x01: +case 0x02: +case 0x03: +case 0x04: +case 0x05: +case 0x06: +case 0x07: +case 0x08: +case 0x09: +case 0x0A: +case 0x0B: +case 0x0C: +case 0x0D: +case 0x0E: +case 0x0F: +case 0x10: +case 0x11: +case 0x12: +case 0x13: +case 0x14: +case 0x15: +case 0x16: +case 0x17: +case 0x18: +case 0x19: +case 0x1A: +case 0x1B: +case 0x1C: +case 0x1D: +case 0x1E: +case 0x1F: +case 0x20: +case 0x21: +case 0x22: +case 0x23: +case 0x24: +case 0x25: +case 0x26: +case 0x27: +case 0x28: +case 0x29: +case 0x2A: +case 0x2B: +case 0x2C: +case 0x2D: +case 0x2E: +case 0x2F: +case 0x30: +case 0x31: +case 0x32: +case 0x33: +case 0x34: +case 0x35: +case 0x36: +case 0x37: +case 0x38: +case 0x39: +case 0x3A: +case 0x3B: +case 0x3C: +case 0x3D: +case 0x3E: +case 0x3F: +case 0x40: +case 0x41: +case 0x42: +case 0x43: +case 0x44: +case 0x45: +case 0x46: +case 0x47: +case 0x48: +case 0x49: +case 0x4A: +case 0x4B: +case 0x4C: +case 0x4D: +case 0x4E: +case 0x4F: +case 0x50: +case 0x51: +case 0x52: +case 0x53: +case 0x54: +case 0x55: +case 0x56: +case 0x57: +case 0x58: +case 0x59: +case 0x5A: +case 0x5B: +case 0x5C: +case 0x5D: +case 0x5E: +case 0x5F: +case 0x60: +case 0x61: +case 0x62: +case 0x63: +case 0x64: +case 0x65: +case 0x66: +case 0x67: +case 0x68: +case 0x69: +case 0x6A: +case 0x6B: +case 0x6C: +case 0x6D: +case 0x6E: +case 0x6F: +case 0x70: +case 0x71: +case 0x72: +case 0x73: +case 0x74: +case 0x75: +case 0x76: +case 0x77: +case 0x78: +case 0x79: +case 0x7A: +case 0x7B: +case 0x7C: +case 0x7D: +case 0x7E: +case 0x7F: +return static_cast(current); + +// fixmap +case 0x80: +case 0x81: +case 0x82: +case 0x83: +case 0x84: +case 0x85: +case 0x86: +case 0x87: +case 0x88: +case 0x89: +case 0x8A: +case 0x8B: +case 0x8C: +case 0x8D: +case 0x8E: +case 0x8F: +{ +return get_msgpack_object(current & 0x0F); +} + +// fixarray +case 0x90: +case 0x91: +case 0x92: +case 0x93: +case 0x94: +case 0x95: +case 0x96: +case 0x97: +case 0x98: +case 0x99: +case 0x9A: +case 0x9B: +case 0x9C: +case 0x9D: +case 0x9E: +case 0x9F: +{ +return get_msgpack_array(current & 0x0F); +} + +// fixstr +case 0xA0: +case 0xA1: +case 0xA2: +case 0xA3: +case 0xA4: +case 0xA5: +case 0xA6: +case 0xA7: +case 0xA8: +case 0xA9: +case 0xAA: +case 0xAB: +case 0xAC: +case 0xAD: +case 0xAE: +case 0xAF: +case 0xB0: +case 0xB1: +case 0xB2: +case 0xB3: +case 0xB4: +case 0xB5: +case 0xB6: +case 0xB7: +case 0xB8: +case 0xB9: +case 0xBA: +case 0xBB: +case 0xBC: +case 0xBD: +case 0xBE: +case 0xBF: +return get_msgpack_string(); + +case 0xC0: // nil +return value_t::null; + +case 0xC2: // false +return false; + +case 0xC3: // true +return true; + +case 0xCA: // float 32 +return get_number(); + +case 0xCB: // float 64 +return get_number(); + +case 0xCC: // uint 8 +return get_number(); + +case 0xCD: // uint 16 +return get_number(); + +case 0xCE: // uint 32 +return get_number(); + +case 0xCF: // uint 64 +return get_number(); + +case 0xD0: // int 8 +return get_number(); + +case 0xD1: // int 16 +return get_number(); + +case 0xD2: // int 32 +return get_number(); + +case 0xD3: // int 64 +return get_number(); + +case 0xD9: // str 8 +case 0xDA: // str 16 +case 0xDB: // str 32 +return get_msgpack_string(); + +case 0xDC: // array 16 +{ +return get_msgpack_array(get_number()); +} + +case 0xDD: // array 32 +{ +return get_msgpack_array(get_number()); +} + +case 0xDE: // map 16 +{ +return get_msgpack_object(get_number()); +} + +case 0xDF: // map 32 +{ +return get_msgpack_object(get_number()); +} + +// positive fixint +case 0xE0: +case 0xE1: +case 0xE2: +case 0xE3: +case 0xE4: +case 0xE5: +case 0xE6: +case 0xE7: +case 0xE8: +case 0xE9: +case 0xEA: +case 0xEB: +case 0xEC: +case 0xED: +case 0xEE: +case 0xEF: +case 0xF0: +case 0xF1: +case 0xF2: +case 0xF3: +case 0xF4: +case 0xF5: +case 0xF6: +case 0xF7: +case 0xF8: +case 0xF9: +case 0xFA: +case 0xFB: +case 0xFC: +case 0xFD: +case 0xFE: +case 0xFF: +return static_cast(current); + +default: // anything else +{ +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; +JSON_THROW(parse_error::create(112, chars_read, +"error reading MessagePack; last byte: 0x" + ss.str())); +} +} +} + +/*! + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + */ +BasicJsonType parse_ubjson_internal(const bool get_char = true) +{ +return get_ubjson_value(get_char ? get_ignore_noop() : current); +} + +/*! + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a -'ve valued + `std::char_traits::eof()` in that case. + + @return character read from the input + */ +int get() +{ +++chars_read; +return (current = ia->get_character()); +} + +/*! + @return character read from the input after ignoring all 'N' entries + */ +int get_ignore_noop() +{ +do +{ +get(); +} +while (current == 'N'); + +return current; +} + +/* + @brief read a number from the input + + @tparam NumberType the type of the number + + @return number of type @a NumberType + + @note This function needs to respect the system's endianess, because + bytes in CBOR and MessagePack are stored in network order (big + endian) and therefore need reordering on little endian systems. + + @throw parse_error.110 if input has less than `sizeof(NumberType)` bytes + */ +template NumberType get_number() +{ +// step 1: read input into array with system's byte order +std::array vec; +for (std::size_t i = 0; i < sizeof(NumberType); ++i) +{ +get(); +unexpect_eof(); + +// reverse byte order prior to conversion if necessary +if (is_little_endian) +{ +vec[sizeof(NumberType) - i - 1] = static_cast(current); +} +else +{ +vec[i] = static_cast(current); // LCOV_EXCL_LINE +} +} + +// step 2: convert array into number of type T and return +NumberType result; +std::memcpy(&result, vec.data(), sizeof(NumberType)); +return result; +} + +/*! + @brief create a string by reading characters from the input + + @param[in] len number of bytes to read + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref unexpect_eof() detects the end of + the input before we run out of string memory. + + @return string created by reading @a len bytes + + @throw parse_error.110 if input has less than @a len bytes + */ +template +string_t get_string(const NumberType len) +{ +string_t result; +std::generate_n(std::back_inserter(result), len, [this]() +{ +get(); +unexpect_eof(); +return static_cast(current); +}); +return result; +} + +/*! + @brief reads a CBOR string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + Additionally, CBOR's strings with indefinite lengths are supported. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ +string_t get_cbor_string() +{ +unexpect_eof(); + +switch (current) +{ +// UTF-8 string (0x00..0x17 bytes follow) +case 0x60: +case 0x61: +case 0x62: +case 0x63: +case 0x64: +case 0x65: +case 0x66: +case 0x67: +case 0x68: +case 0x69: +case 0x6A: +case 0x6B: +case 0x6C: +case 0x6D: +case 0x6E: +case 0x6F: +case 0x70: +case 0x71: +case 0x72: +case 0x73: +case 0x74: +case 0x75: +case 0x76: +case 0x77: +{ +return get_string(current & 0x1F); +} + +case 0x78: // UTF-8 string (one-byte uint8_t for n follows) +{ +return get_string(get_number()); +} + +case 0x79: // UTF-8 string (two-byte uint16_t for n follow) +{ +return get_string(get_number()); +} + +case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) +{ +return get_string(get_number()); +} + +case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) +{ +return get_string(get_number()); +} + +case 0x7F: // UTF-8 string (indefinite length) +{ +string_t result; +while (get() != 0xFF) +{ +unexpect_eof(); +result.push_back(static_cast(current)); +} +return result; +} + +default: +{ +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; +JSON_THROW(parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + ss.str())); +} +} +} + +template +BasicJsonType get_cbor_array(const NumberType len) +{ +BasicJsonType result = value_t::array; +std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() +{ +return parse_cbor_internal(); +}); +return result; +} + +template +BasicJsonType get_cbor_object(const NumberType len) +{ +BasicJsonType result = value_t::object; +std::generate_n(std::inserter(*result.m_value.object, +result.m_value.object->end()), +len, [this]() +{ +get(); +auto key = get_cbor_string(); +auto val = parse_cbor_internal(); +return std::make_pair(std::move(key), std::move(val)); +}); +return result; +} + +/*! + @brief reads a MessagePack string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ +string_t get_msgpack_string() +{ +unexpect_eof(); + +switch (current) +{ +// fixstr +case 0xA0: +case 0xA1: +case 0xA2: +case 0xA3: +case 0xA4: +case 0xA5: +case 0xA6: +case 0xA7: +case 0xA8: +case 0xA9: +case 0xAA: +case 0xAB: +case 0xAC: +case 0xAD: +case 0xAE: +case 0xAF: +case 0xB0: +case 0xB1: +case 0xB2: +case 0xB3: +case 0xB4: +case 0xB5: +case 0xB6: +case 0xB7: +case 0xB8: +case 0xB9: +case 0xBA: +case 0xBB: +case 0xBC: +case 0xBD: +case 0xBE: +case 0xBF: +{ +return get_string(current & 0x1F); +} + +case 0xD9: // str 8 +{ +return get_string(get_number()); +} + +case 0xDA: // str 16 +{ +return get_string(get_number()); +} + +case 0xDB: // str 32 +{ +return get_string(get_number()); +} + +default: +{ +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; +JSON_THROW(parse_error::create(113, chars_read, +"expected a MessagePack string; last byte: 0x" + ss.str())); +} +} +} + +template +BasicJsonType get_msgpack_array(const NumberType len) +{ +BasicJsonType result = value_t::array; +std::generate_n(std::back_inserter(*result.m_value.array), len, [this]() +{ +return parse_msgpack_internal(); +}); +return result; +} + +template +BasicJsonType get_msgpack_object(const NumberType len) +{ +BasicJsonType result = value_t::object; +std::generate_n(std::inserter(*result.m_value.object, +result.m_value.object->end()), +len, [this]() +{ +get(); +auto key = get_msgpack_string(); +auto val = parse_msgpack_internal(); +return std::make_pair(std::move(key), std::move(val)); +}); +return result; +} + +/*! + @brief reads a UBJSON string + + This function is either called after reading the 'S' byte explicitly + indicating a string, or in case of an object key where the 'S' byte can be + left out. + + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpected byte is read + */ +string_t get_ubjson_string(const bool get_char = true) +{ +if (get_char) +{ +get(); // TODO: may we ignore N here? +} + +unexpect_eof(); + +switch (current) +{ +case 'U': +return get_string(get_number()); +case 'i': +return get_string(get_number()); +case 'I': +return get_string(get_number()); +case 'l': +return get_string(get_number()); +case 'L': +return get_string(get_number()); +default: +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; +JSON_THROW(parse_error::create(113, chars_read, +"expected a UBJSON string; last byte: 0x" + ss.str())); +} +} + +/*! + @brief determine the type and size for a container + + In the optimized UBJSON format, a type and a size can be provided to allow + for a more compact representation. + + @return pair of the size and the type + */ +std::pair get_ubjson_size_type() +{ +std::size_t sz = string_t::npos; +int tc = 0; + +get_ignore_noop(); + +if (current == '$') +{ +tc = get(); // must not ignore 'N', because 'N' maybe the type +unexpect_eof(); + +get_ignore_noop(); +if (current != '#') +{ +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; +JSON_THROW(parse_error::create(112, chars_read, +"expected '#' after UBJSON type information; last byte: 0x" + ss.str())); +} +sz = parse_ubjson_internal(); +} +else if (current == '#') +{ +sz = parse_ubjson_internal(); +} + +return std::make_pair(sz, tc); +} + +BasicJsonType get_ubjson_value(const int prefix) +{ +switch (prefix) +{ +case std::char_traits::eof(): // EOF +JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + +case 'T': // true +return true; +case 'F': // false +return false; + +case 'Z': // null +return nullptr; + +case 'U': +return get_number(); +case 'i': +return get_number(); +case 'I': +return get_number(); +case 'l': +return get_number(); +case 'L': +return get_number(); +case 'd': +return get_number(); +case 'D': +return get_number(); + +case 'C': // char +{ +get(); +unexpect_eof(); +if (JSON_UNLIKELY(current > 127)) +{ +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; +JSON_THROW(parse_error::create(113, chars_read, +"byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + ss.str())); +} +return string_t(1, static_cast(current)); +} + +case 'S': // string +return get_ubjson_string(); + +case '[': // array +return get_ubjson_array(); + +case '{': // object +return get_ubjson_object(); + +default: // anything else +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; +JSON_THROW(parse_error::create(112, chars_read, +"error reading UBJSON; last byte: 0x" + ss.str())); +} +} + +BasicJsonType get_ubjson_array() +{ +BasicJsonType result = value_t::array; +const auto size_and_type = get_ubjson_size_type(); + +if (size_and_type.first != string_t::npos) +{ +if (size_and_type.second != 0) +{ +if (size_and_type.second != 'N') +std::generate_n(std::back_inserter(*result.m_value.array), +size_and_type.first, [this, size_and_type]() +{ +return get_ubjson_value(size_and_type.second); +}); +} +else +{ +std::generate_n(std::back_inserter(*result.m_value.array), +size_and_type.first, [this]() +{ +return parse_ubjson_internal(); +}); +} +} +else +{ +while (current != ']') +{ +result.push_back(parse_ubjson_internal(false)); +get_ignore_noop(); +} +} + +return result; +} + +BasicJsonType get_ubjson_object() +{ +BasicJsonType result = value_t::object; +const auto size_and_type = get_ubjson_size_type(); + +if (size_and_type.first != string_t::npos) +{ +if (size_and_type.second != 0) +{ +std::generate_n(std::inserter(*result.m_value.object, +result.m_value.object->end()), +size_and_type.first, [this, size_and_type]() +{ +auto key = get_ubjson_string(); +auto val = get_ubjson_value(size_and_type.second); +return std::make_pair(std::move(key), std::move(val)); +}); +} +else +{ +std::generate_n(std::inserter(*result.m_value.object, +result.m_value.object->end()), +size_and_type.first, [this]() +{ +auto key = get_ubjson_string(); +auto val = parse_ubjson_internal(); +return std::make_pair(std::move(key), std::move(val)); +}); +} +} +else +{ +while (current != '}') +{ +auto key = get_ubjson_string(false); +result[std::move(key)] = parse_ubjson_internal(); +get_ignore_noop(); +} +} + +return result; +} + +/*! + @brief throw if end of input is not reached + @throw parse_error.110 if input not ended + */ +void expect_eof() const +{ +if (JSON_UNLIKELY(current != std::char_traits::eof())) +{ +JSON_THROW(parse_error::create(110, chars_read, "expected end of input")); +} +} + +/*! + @briefthrow if end of input is reached + @throw parse_error.110 if input ended + */ +void unexpect_eof() const +{ +if (JSON_UNLIKELY(current == std::char_traits::eof())) +{ +JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); +} +} + +private: +/// input adapter +input_adapter_t ia = nullptr; + +/// the current character +int current = std::char_traits::eof(); + +/// the number of characters read +std::size_t chars_read = 0; + +/// whether we can assume little endianess +const bool is_little_endian = little_endianess(); +}; +} +} + +// #include + + +#include // reverse +#include // array +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // numeric_limits + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// binary writer // +/////////////////// + +/*! +@brief serialization to CBOR and MessagePack values +*/ +template +class binary_writer +{ +public: +/*! + @brief create a binary writer + + @param[in] adapter output adapter to write to + */ +explicit binary_writer(output_adapter_t adapter) : oa(adapter) +{ +assert(oa); +} + +/*! + @brief[in] j JSON value to serialize + */ +void write_cbor(const BasicJsonType& j) +{ +switch (j.type()) +{ +case value_t::null: +{ +oa->write_character(static_cast(0xF6)); +break; +} + +case value_t::boolean: +{ +oa->write_character(j.m_value.boolean +? static_cast(0xF5) +: static_cast(0xF4)); +break; +} + +case value_t::number_integer: +{ +if (j.m_value.number_integer >= 0) +{ +// CBOR does not differentiate between positive signed +// integers and unsigned integers. Therefore, we used the +// code from the value_t::number_unsigned case here. +if (j.m_value.number_integer <= 0x17) +{ +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x18)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x19)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x1A)); +write_number(static_cast(j.m_value.number_integer)); +} +else +{ +oa->write_character(static_cast(0x1B)); +write_number(static_cast(j.m_value.number_integer)); +} +} +else +{ +// The conversions below encode the sign in the first +// byte, and the value is converted to a positive number. +const auto positive_number = -1 - j.m_value.number_integer; +if (j.m_value.number_integer >= -24) +{ +write_number(static_cast(0x20 + positive_number)); +} +else if (positive_number <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x38)); +write_number(static_cast(positive_number)); +} +else if (positive_number <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x39)); +write_number(static_cast(positive_number)); +} +else if (positive_number <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x3A)); +write_number(static_cast(positive_number)); +} +else +{ +oa->write_character(static_cast(0x3B)); +write_number(static_cast(positive_number)); +} +} +break; +} + +case value_t::number_unsigned: +{ +if (j.m_value.number_unsigned <= 0x17) +{ +write_number(static_cast(j.m_value.number_unsigned)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x18)); +write_number(static_cast(j.m_value.number_unsigned)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x19)); +write_number(static_cast(j.m_value.number_unsigned)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x1A)); +write_number(static_cast(j.m_value.number_unsigned)); +} +else +{ +oa->write_character(static_cast(0x1B)); +write_number(static_cast(j.m_value.number_unsigned)); +} +break; +} + +case value_t::number_float: // Double-Precision Float +{ +oa->write_character(static_cast(0xFB)); +write_number(j.m_value.number_float); +break; +} + +case value_t::string: +{ +// step 1: write control byte and the string length +const auto N = j.m_value.string->size(); +if (N <= 0x17) +{ +write_number(static_cast(0x60 + N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x78)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x79)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x7A)); +write_number(static_cast(N)); +} +// LCOV_EXCL_START +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x7B)); +write_number(static_cast(N)); +} +// LCOV_EXCL_STOP + +// step 2: write the string +oa->write_characters( +reinterpret_cast(j.m_value.string->c_str()), +j.m_value.string->size()); +break; +} + +case value_t::array: +{ +// step 1: write control byte and the array size +const auto N = j.m_value.array->size(); +if (N <= 0x17) +{ +write_number(static_cast(0x80 + N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x98)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x99)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x9A)); +write_number(static_cast(N)); +} +// LCOV_EXCL_START +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0x9B)); +write_number(static_cast(N)); +} +// LCOV_EXCL_STOP + +// step 2: write each element +for (const auto& el : *j.m_value.array) +{ +write_cbor(el); +} +break; +} + +case value_t::object: +{ +// step 1: write control byte and the object size +const auto N = j.m_value.object->size(); +if (N <= 0x17) +{ +write_number(static_cast(0xA0 + N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0xB8)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0xB9)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0xBA)); +write_number(static_cast(N)); +} +// LCOV_EXCL_START +else if (N <= (std::numeric_limits::max)()) +{ +oa->write_character(static_cast(0xBB)); +write_number(static_cast(N)); +} +// LCOV_EXCL_STOP + +// step 2: write each element +for (const auto& el : *j.m_value.object) +{ +write_cbor(el.first); +write_cbor(el.second); +} +break; +} + +default: +break; +} +} + +/*! + @brief[in] j JSON value to serialize + */ +void write_msgpack(const BasicJsonType& j) +{ +switch (j.type()) +{ +case value_t::null: // nil +{ +oa->write_character(static_cast(0xC0)); +break; +} + +case value_t::boolean: // true and false +{ +oa->write_character(j.m_value.boolean +? static_cast(0xC3) +: static_cast(0xC2)); +break; +} + +case value_t::number_integer: +{ +if (j.m_value.number_integer >= 0) +{ +// MessagePack does not differentiate between positive +// signed integers and unsigned integers. Therefore, we used +// the code from the value_t::number_unsigned case here. +if (j.m_value.number_unsigned < 128) +{ +// positive fixnum +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +// uint 8 +oa->write_character(static_cast(0xCC)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +// uint 16 +oa->write_character(static_cast(0xCD)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +// uint 32 +oa->write_character(static_cast(0xCE)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +// uint 64 +oa->write_character(static_cast(0xCF)); +write_number(static_cast(j.m_value.number_integer)); +} +} +else +{ +if (j.m_value.number_integer >= -32) +{ +// negative fixnum +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_integer >= (std::numeric_limits::min)() and +j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +// int 8 +oa->write_character(static_cast(0xD0)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_integer >= (std::numeric_limits::min)() and +j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +// int 16 +oa->write_character(static_cast(0xD1)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_integer >= (std::numeric_limits::min)() and +j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +// int 32 +oa->write_character(static_cast(0xD2)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_integer >= (std::numeric_limits::min)() and +j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +// int 64 +oa->write_character(static_cast(0xD3)); +write_number(static_cast(j.m_value.number_integer)); +} +} +break; +} + +case value_t::number_unsigned: +{ +if (j.m_value.number_unsigned < 128) +{ +// positive fixnum +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +// uint 8 +oa->write_character(static_cast(0xCC)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +// uint 16 +oa->write_character(static_cast(0xCD)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +// uint 32 +oa->write_character(static_cast(0xCE)); +write_number(static_cast(j.m_value.number_integer)); +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +// uint 64 +oa->write_character(static_cast(0xCF)); +write_number(static_cast(j.m_value.number_integer)); +} +break; +} + +case value_t::number_float: // float 64 +{ +oa->write_character(static_cast(0xCB)); +write_number(j.m_value.number_float); +break; +} + +case value_t::string: +{ +// step 1: write control byte and the string length +const auto N = j.m_value.string->size(); +if (N <= 31) +{ +// fixstr +write_number(static_cast(0xA0 | N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +// str 8 +oa->write_character(static_cast(0xD9)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +// str 16 +oa->write_character(static_cast(0xDA)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +// str 32 +oa->write_character(static_cast(0xDB)); +write_number(static_cast(N)); +} + +// step 2: write the string +oa->write_characters( +reinterpret_cast(j.m_value.string->c_str()), +j.m_value.string->size()); +break; +} + +case value_t::array: +{ +// step 1: write control byte and the array size +const auto N = j.m_value.array->size(); +if (N <= 15) +{ +// fixarray +write_number(static_cast(0x90 | N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +// array 16 +oa->write_character(static_cast(0xDC)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +// array 32 +oa->write_character(static_cast(0xDD)); +write_number(static_cast(N)); +} + +// step 2: write each element +for (const auto& el : *j.m_value.array) +{ +write_msgpack(el); +} +break; +} + +case value_t::object: +{ +// step 1: write control byte and the object size +const auto N = j.m_value.object->size(); +if (N <= 15) +{ +// fixmap +write_number(static_cast(0x80 | (N & 0xF))); +} +else if (N <= (std::numeric_limits::max)()) +{ +// map 16 +oa->write_character(static_cast(0xDE)); +write_number(static_cast(N)); +} +else if (N <= (std::numeric_limits::max)()) +{ +// map 32 +oa->write_character(static_cast(0xDF)); +write_number(static_cast(N)); +} + +// step 2: write each element +for (const auto& el : *j.m_value.object) +{ +write_msgpack(el.first); +write_msgpack(el.second); +} +break; +} + +default: +break; +} +} + +/*! + @param[in] j JSON value to serialize + @param[in] use_count whether to use '#' prefixes (optimized format) + @param[in] use_type whether to use '$' prefixes (optimized format) + @param[in] add_prefix whether prefixes need to be used for this value + */ +void write_ubjson(const BasicJsonType& j, const bool use_count, +const bool use_type, const bool add_prefix = true) +{ +switch (j.type()) +{ +case value_t::null: +{ +if (add_prefix) +{ +oa->write_character(static_cast('Z')); +} +break; +} + +case value_t::boolean: +{ +if (add_prefix) +oa->write_character(j.m_value.boolean +? static_cast('T') +: static_cast('F')); +break; +} + +case value_t::number_integer: +{ +write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix); +break; +} + +case value_t::number_unsigned: +{ +write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix); +break; +} + +case value_t::number_float: +{ +write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix); +break; +} + +case value_t::string: +{ +if (add_prefix) +{ +oa->write_character(static_cast('S')); +} +write_number_with_ubjson_prefix(j.m_value.string->size(), true); +oa->write_characters( +reinterpret_cast(j.m_value.string->c_str()), +j.m_value.string->size()); +break; +} + +case value_t::array: +{ +if (add_prefix) +{ +oa->write_character(static_cast('[')); +} + +bool prefix_required = true; +if (use_type and not j.m_value.array->empty()) +{ +assert(use_count); +const char first_prefix = ubjson_prefix(j.front()); +const bool same_prefix = std::all_of(j.begin() + 1, j.end(), +[this, first_prefix](const BasicJsonType & v) +{ +return ubjson_prefix(v) == first_prefix; +}); + +if (same_prefix) +{ +prefix_required = false; +oa->write_character(static_cast('$')); +oa->write_character(static_cast(first_prefix)); +} +} + +if (use_count) +{ +oa->write_character(static_cast('#')); +write_number_with_ubjson_prefix(j.m_value.array->size(), true); +} + +for (const auto& el : *j.m_value.array) +{ +write_ubjson(el, use_count, use_type, prefix_required); +} + +if (not use_count) +{ +oa->write_character(static_cast(']')); +} + +break; +} + +case value_t::object: +{ +if (add_prefix) +{ +oa->write_character(static_cast('{')); +} + +bool prefix_required = true; +if (use_type and not j.m_value.object->empty()) +{ +assert(use_count); +const char first_prefix = ubjson_prefix(j.front()); +const bool same_prefix = std::all_of(j.begin(), j.end(), +[this, first_prefix](const BasicJsonType & v) +{ +return ubjson_prefix(v) == first_prefix; +}); + +if (same_prefix) +{ +prefix_required = false; +oa->write_character(static_cast('$')); +oa->write_character(static_cast(first_prefix)); +} +} + +if (use_count) +{ +oa->write_character(static_cast('#')); +write_number_with_ubjson_prefix(j.m_value.object->size(), true); +} + +for (const auto& el : *j.m_value.object) +{ +write_number_with_ubjson_prefix(el.first.size(), true); +oa->write_characters( +reinterpret_cast(el.first.c_str()), +el.first.size()); +write_ubjson(el.second, use_count, use_type, prefix_required); +} + +if (not use_count) +{ +oa->write_character(static_cast('}')); +} + +break; +} + +default: +break; +} +} + +private: +/* + @brief write a number to output input + + @param[in] n number of type @a NumberType + @tparam NumberType the type of the number + + @note This function needs to respect the system's endianess, because bytes + in CBOR, MessagePack, and UBJSON are stored in network order (big + endian) and therefore need reordering on little endian systems. + */ +template +void write_number(const NumberType n) +{ +// step 1: write number to array of length NumberType +std::array vec; +std::memcpy(vec.data(), &n, sizeof(NumberType)); + +// step 2: write array to output (with possible reordering) +if (is_little_endian) +{ +// reverse byte order prior to conversion if necessary +std::reverse(vec.begin(), vec.end()); +} + +oa->write_characters(vec.data(), sizeof(NumberType)); +} + +template +void write_number_with_ubjson_prefix(const NumberType n, +const bool add_prefix) +{ +if (std::is_floating_point::value) +{ +if (add_prefix) +{ +oa->write_character(static_cast('D')); // float64 +} +write_number(n); +} +else if (std::is_unsigned::value) +{ +if (n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('i')); // int8 +} +write_number(static_cast(n)); +} +else if (n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('U')); // uint8 +} +write_number(static_cast(n)); +} +else if (n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('I')); // int16 +} +write_number(static_cast(n)); +} +else if (n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('l')); // int32 +} +write_number(static_cast(n)); +} +else if (n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('L')); // int64 +} +write_number(static_cast(n)); +} +else +{ +JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); +} +} +else +{ +if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('i')); // int8 +} +write_number(static_cast(n)); +} +else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('U')); // uint8 +} +write_number(static_cast(n)); +} +else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('I')); // int16 +} +write_number(static_cast(n)); +} +else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('l')); // int32 +} +write_number(static_cast(n)); +} +else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) +{ +if (add_prefix) +{ +oa->write_character(static_cast('L')); // int64 +} +write_number(static_cast(n)); +} +// LCOV_EXCL_START +else +{ +JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); +} +// LCOV_EXCL_STOP +} +} + +/*! + @brief determine the type prefix of container values + + @note This function does not need to be 100% accurate when it comes to + integer limits. In case a number exceeds the limits of int64_t, + this will be detected by a later call to function + write_number_with_ubjson_prefix. Therefore, we return 'L' for any + value that does not fit the previous limits. + */ +char ubjson_prefix(const BasicJsonType& j) const noexcept +{ +switch (j.type()) +{ +case value_t::null: +return 'Z'; + +case value_t::boolean: +return j.m_value.boolean ? 'T' : 'F'; + +case value_t::number_integer: +{ +if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +return 'i'; +} +else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +return 'U'; +} +else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +return 'I'; +} +else if ((std::numeric_limits::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits::max)()) +{ +return 'l'; +} +else // no check and assume int64_t (see note above) +{ +return 'L'; +} +} + +case value_t::number_unsigned: +{ +if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +return 'i'; +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +return 'U'; +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +return 'I'; +} +else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) +{ +return 'l'; +} +else // no check and assume int64_t (see note above) +{ +return 'L'; +} +} + +case value_t::number_float: +return 'D'; + +case value_t::string: +return 'S'; + +case value_t::array: +return '['; + +case value_t::object: +return '{'; + +default: // discarded values +return 'N'; +} +} + +private: +/// whether we can assume little endianess +const bool is_little_endian = binary_reader::little_endianess(); + +/// the output +output_adapter_t oa = nullptr; +}; +} +} + +// #include + + +#include // reverse, remove, fill, find, none_of +#include // array +#include // assert +#include // and, or +#include // localeconv, lconv +#include // labs, isfinite, isnan, signbit +#include // size_t, ptrdiff_t +#include // uint8_t +#include // snprintf +#include // setfill +#include // next +#include // numeric_limits +#include // string +#include // stringstream +#include // is_same + +// #include + +// #include + + +#include // assert +#include // or, and, not +#include // signbit, isfinite +#include // intN_t, uintN_t +#include // memcpy, memmove + +namespace nlohmann +{ +namespace detail +{ + +/*! +@brief implements the Grisu2 algorithm for binary to decimal floating-point +conversion. + +This implementation is a slightly modified version of the reference +implementation which may be obtained from +http://florian.loitsch.com/publications (bench.tar.gz). + +The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch. + +For a detailed description of the algorithm see: + +[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with + Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming + Language Design and Implementation, PLDI 2010 +[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately", + Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language + Design and Implementation, PLDI 1996 +*/ +namespace dtoa_impl +{ + +template +Target reinterpret_bits(const Source source) +{ +static_assert(sizeof(Target) == sizeof(Source), "size mismatch"); + +Target target; +std::memcpy(&target, &source, sizeof(Source)); +return target; +} + +struct diyfp // f * 2^e +{ +static constexpr int kPrecision = 64; // = q + +uint64_t f; +int e; + +constexpr diyfp() noexcept : f(0), e(0) {} +constexpr diyfp(uint64_t f_, int e_) noexcept : f(f_), e(e_) {} + +/*! + @brief returns x - y + @pre x.e == y.e and x.f >= y.f + */ +static diyfp sub(const diyfp& x, const diyfp& y) noexcept +{ +assert(x.e == y.e); +assert(x.f >= y.f); + +return diyfp(x.f - y.f, x.e); +} + +/*! + @brief returns x * y + @note The result is rounded. (Only the upper q bits are returned.) + */ +static diyfp mul(const diyfp& x, const diyfp& y) noexcept +{ +static_assert(kPrecision == 64, "internal error"); + +// Computes: +// f = round((x.f * y.f) / 2^q) +// e = x.e + y.e + q + +// Emulate the 64-bit * 64-bit multiplication: +// +// p = u * v +// = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi) +// = (u_lo v_lo ) + 2^32 ((u_lo v_hi ) + (u_hi v_lo )) + 2^64 (u_hi v_hi ) +// = (p0 ) + 2^32 ((p1 ) + (p2 )) + 2^64 (p3 ) +// = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3 ) +// = (p0_lo ) + 2^32 (p0_hi + p1_lo + p2_lo ) + 2^64 (p1_hi + p2_hi + p3) +// = (p0_lo ) + 2^32 (Q ) + 2^64 (H ) +// = (p0_lo ) + 2^32 (Q_lo + 2^32 Q_hi ) + 2^64 (H ) +// +// (Since Q might be larger than 2^32 - 1) +// +// = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H) +// +// (Q_hi + H does not overflow a 64-bit int) +// +// = p_lo + 2^64 p_hi + +const uint64_t u_lo = x.f & 0xFFFFFFFF; +const uint64_t u_hi = x.f >> 32; +const uint64_t v_lo = y.f & 0xFFFFFFFF; +const uint64_t v_hi = y.f >> 32; + +const uint64_t p0 = u_lo * v_lo; +const uint64_t p1 = u_lo * v_hi; +const uint64_t p2 = u_hi * v_lo; +const uint64_t p3 = u_hi * v_hi; + +const uint64_t p0_hi = p0 >> 32; +const uint64_t p1_lo = p1 & 0xFFFFFFFF; +const uint64_t p1_hi = p1 >> 32; +const uint64_t p2_lo = p2 & 0xFFFFFFFF; +const uint64_t p2_hi = p2 >> 32; + +uint64_t Q = p0_hi + p1_lo + p2_lo; + +// The full product might now be computed as +// +// p_hi = p3 + p2_hi + p1_hi + (Q >> 32) +// p_lo = p0_lo + (Q << 32) +// +// But in this particular case here, the full p_lo is not required. +// Effectively we only need to add the highest bit in p_lo to p_hi (and +// Q_hi + 1 does not overflow). + +Q += uint64_t{1} << (64 - 32 - 1); // round, ties up + +const uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32); + +return diyfp(h, x.e + y.e + 64); +} + +/*! + @brief normalize x such that the significand is >= 2^(q-1) + @pre x.f != 0 + */ +static diyfp normalize(diyfp x) noexcept +{ +assert(x.f != 0); + +while ((x.f >> 63) == 0) +{ +x.f <<= 1; +x.e--; +} + +return x; +} + +/*! + @brief normalize x such that the result has the exponent E + @pre e >= x.e and the upper e - x.e bits of x.f must be zero. + */ +static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept +{ +const int delta = x.e - target_exponent; + +assert(delta >= 0); +assert(((x.f << delta) >> delta) == x.f); + +return diyfp(x.f << delta, target_exponent); +} +}; + +struct boundaries +{ +diyfp w; +diyfp minus; +diyfp plus; +}; + +/*! +Compute the (normalized) diyfp representing the input number 'value' and its +boundaries. + +@pre value must be finite and positive +*/ +template +boundaries compute_boundaries(FloatType value) +{ +assert(std::isfinite(value)); +assert(value > 0); + +// Convert the IEEE representation into a diyfp. +// +// If v is denormal: +// value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1)) +// If v is normalized: +// value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1)) + +static_assert(std::numeric_limits::is_iec559, +"internal error: dtoa_short requires an IEEE-754 floating-point implementation"); + +constexpr int kPrecision = std::numeric_limits::digits; // = p (includes the hidden bit) +constexpr int kBias = std::numeric_limits::max_exponent - 1 + (kPrecision - 1); +constexpr int kMinExp = 1 - kBias; +constexpr uint64_t kHiddenBit = uint64_t{1} << (kPrecision - 1); // = 2^(p-1) + +using bits_type = typename std::conditional< kPrecision == 24, uint32_t, uint64_t >::type; + +const uint64_t bits = reinterpret_bits(value); +const uint64_t E = bits >> (kPrecision - 1); +const uint64_t F = bits & (kHiddenBit - 1); + +const bool is_denormal = (E == 0); +const diyfp v = is_denormal +? diyfp(F, kMinExp) +: diyfp(F + kHiddenBit, static_cast(E) - kBias); + +// Compute the boundaries m- and m+ of the floating-point value +// v = f * 2^e. +// +// Determine v- and v+, the floating-point predecessor and successor if v, +// respectively. +// +// v- = v - 2^e if f != 2^(p-1) or e == e_min (A) +// = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B) +// +// v+ = v + 2^e +// +// Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_ +// between m- and m+ round to v, regardless of how the input rounding +// algorithm breaks ties. +// +// ---+-------------+-------------+-------------+-------------+--- (A) +// v- m- v m+ v+ +// +// -----------------+------+------+-------------+-------------+--- (B) +// v- m- v m+ v+ + +const bool lower_boundary_is_closer = (F == 0 and E > 1); +const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); +const diyfp m_minus = lower_boundary_is_closer +? diyfp(4 * v.f - 1, v.e - 2) // (B) +: diyfp(2 * v.f - 1, v.e - 1); // (A) + +// Determine the normalized w+ = m+. +const diyfp w_plus = diyfp::normalize(m_plus); + +// Determine w- = m- such that e_(w-) = e_(w+). +const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e); + +return {diyfp::normalize(v), w_minus, w_plus}; +} + +// Given normalized diyfp w, Grisu needs to find a (normalized) cached +// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies +// within a certain range [alpha, gamma] (Definition 3.2 from [1]) +// +// alpha <= e = e_c + e_w + q <= gamma +// +// or +// +// f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q +// <= f_c * f_w * 2^gamma +// +// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies +// +// 2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma +// +// or +// +// 2^(q - 2 + alpha) <= c * w < 2^(q + gamma) +// +// The choice of (alpha,gamma) determines the size of the table and the form of +// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well +// in practice: +// +// The idea is to cut the number c * w = f * 2^e into two parts, which can be +// processed independently: An integral part p1, and a fractional part p2: +// +// f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e +// = (f div 2^-e) + (f mod 2^-e) * 2^e +// = p1 + p2 * 2^e +// +// The conversion of p1 into decimal form requires a series of divisions and +// modulos by (a power of) 10. These operations are faster for 32-bit than for +// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be +// achieved by choosing +// +// -e >= 32 or e <= -32 := gamma +// +// In order to convert the fractional part +// +// p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ... +// +// into decimal form, the fraction is repeatedly multiplied by 10 and the digits +// d[-i] are extracted in order: +// +// (10 * p2) div 2^-e = d[-1] +// (10 * p2) mod 2^-e = d[-2] / 10^1 + ... +// +// The multiplication by 10 must not overflow. It is sufficient to choose +// +// 10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64. +// +// Since p2 = f mod 2^-e < 2^-e, +// +// -e <= 60 or e >= -60 := alpha + +constexpr int kAlpha = -60; +constexpr int kGamma = -32; + +struct cached_power // c = f * 2^e ~= 10^k +{ +uint64_t f; +int e; +int k; +}; + +/*! +For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached +power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c +satisfies (Definition 3.2 from [1]) + + alpha <= e_c + e + q <= gamma. +*/ +inline cached_power get_cached_power_for_binary_exponent(int e) +{ +// Now +// +// alpha <= e_c + e + q <= gamma (1) +// ==> f_c * 2^alpha <= c * 2^e * 2^q +// +// and since the c's are normalized, 2^(q-1) <= f_c, +// +// ==> 2^(q - 1 + alpha) <= c * 2^(e + q) +// ==> 2^(alpha - e - 1) <= c +// +// If c were an exakt power of ten, i.e. c = 10^k, one may determine k as +// +// k = ceil( log_10( 2^(alpha - e - 1) ) ) +// = ceil( (alpha - e - 1) * log_10(2) ) +// +// From the paper: +// "In theory the result of the procedure could be wrong since c is rounded, +// and the computation itself is approximated [...]. In practice, however, +// this simple function is sufficient." +// +// For IEEE double precision floating-point numbers converted into +// normalized diyfp's w = f * 2^e, with q = 64, +// +// e >= -1022 (min IEEE exponent) +// -52 (p - 1) +// -52 (p - 1, possibly normalize denormal IEEE numbers) +// -11 (normalize the diyfp) +// = -1137 +// +// and +// +// e <= +1023 (max IEEE exponent) +// -52 (p - 1) +// -11 (normalize the diyfp) +// = 960 +// +// This binary exponent range [-1137,960] results in a decimal exponent +// range [-307,324]. One does not need to store a cached power for each +// k in this range. For each such k it suffices to find a cached power +// such that the exponent of the product lies in [alpha,gamma]. +// This implies that the difference of the decimal exponents of adjacent +// table entries must be less than or equal to +// +// floor( (gamma - alpha) * log_10(2) ) = 8. +// +// (A smaller distance gamma-alpha would require a larger table.) + +// NB: +// Actually this function returns c, such that -60 <= e_c + e + 64 <= -34. + +constexpr int kCachedPowersSize = 79; +constexpr int kCachedPowersMinDecExp = -300; +constexpr int kCachedPowersDecStep = 8; + +static constexpr cached_power kCachedPowers[] = +{ +{ 0xAB70FE17C79AC6CA, -1060, -300 }, +{ 0xFF77B1FCBEBCDC4F, -1034, -292 }, +{ 0xBE5691EF416BD60C, -1007, -284 }, +{ 0x8DD01FAD907FFC3C, -980, -276 }, +{ 0xD3515C2831559A83, -954, -268 }, +{ 0x9D71AC8FADA6C9B5, -927, -260 }, +{ 0xEA9C227723EE8BCB, -901, -252 }, +{ 0xAECC49914078536D, -874, -244 }, +{ 0x823C12795DB6CE57, -847, -236 }, +{ 0xC21094364DFB5637, -821, -228 }, +{ 0x9096EA6F3848984F, -794, -220 }, +{ 0xD77485CB25823AC7, -768, -212 }, +{ 0xA086CFCD97BF97F4, -741, -204 }, +{ 0xEF340A98172AACE5, -715, -196 }, +{ 0xB23867FB2A35B28E, -688, -188 }, +{ 0x84C8D4DFD2C63F3B, -661, -180 }, +{ 0xC5DD44271AD3CDBA, -635, -172 }, +{ 0x936B9FCEBB25C996, -608, -164 }, +{ 0xDBAC6C247D62A584, -582, -156 }, +{ 0xA3AB66580D5FDAF6, -555, -148 }, +{ 0xF3E2F893DEC3F126, -529, -140 }, +{ 0xB5B5ADA8AAFF80B8, -502, -132 }, +{ 0x87625F056C7C4A8B, -475, -124 }, +{ 0xC9BCFF6034C13053, -449, -116 }, +{ 0x964E858C91BA2655, -422, -108 }, +{ 0xDFF9772470297EBD, -396, -100 }, +{ 0xA6DFBD9FB8E5B88F, -369, -92 }, +{ 0xF8A95FCF88747D94, -343, -84 }, +{ 0xB94470938FA89BCF, -316, -76 }, +{ 0x8A08F0F8BF0F156B, -289, -68 }, +{ 0xCDB02555653131B6, -263, -60 }, +{ 0x993FE2C6D07B7FAC, -236, -52 }, +{ 0xE45C10C42A2B3B06, -210, -44 }, +{ 0xAA242499697392D3, -183, -36 }, +{ 0xFD87B5F28300CA0E, -157, -28 }, +{ 0xBCE5086492111AEB, -130, -20 }, +{ 0x8CBCCC096F5088CC, -103, -12 }, +{ 0xD1B71758E219652C, -77, -4 }, +{ 0x9C40000000000000, -50, 4 }, +{ 0xE8D4A51000000000, -24, 12 }, +{ 0xAD78EBC5AC620000, 3, 20 }, +{ 0x813F3978F8940984, 30, 28 }, +{ 0xC097CE7BC90715B3, 56, 36 }, +{ 0x8F7E32CE7BEA5C70, 83, 44 }, +{ 0xD5D238A4ABE98068, 109, 52 }, +{ 0x9F4F2726179A2245, 136, 60 }, +{ 0xED63A231D4C4FB27, 162, 68 }, +{ 0xB0DE65388CC8ADA8, 189, 76 }, +{ 0x83C7088E1AAB65DB, 216, 84 }, +{ 0xC45D1DF942711D9A, 242, 92 }, +{ 0x924D692CA61BE758, 269, 100 }, +{ 0xDA01EE641A708DEA, 295, 108 }, +{ 0xA26DA3999AEF774A, 322, 116 }, +{ 0xF209787BB47D6B85, 348, 124 }, +{ 0xB454E4A179DD1877, 375, 132 }, +{ 0x865B86925B9BC5C2, 402, 140 }, +{ 0xC83553C5C8965D3D, 428, 148 }, +{ 0x952AB45CFA97A0B3, 455, 156 }, +{ 0xDE469FBD99A05FE3, 481, 164 }, +{ 0xA59BC234DB398C25, 508, 172 }, +{ 0xF6C69A72A3989F5C, 534, 180 }, +{ 0xB7DCBF5354E9BECE, 561, 188 }, +{ 0x88FCF317F22241E2, 588, 196 }, +{ 0xCC20CE9BD35C78A5, 614, 204 }, +{ 0x98165AF37B2153DF, 641, 212 }, +{ 0xE2A0B5DC971F303A, 667, 220 }, +{ 0xA8D9D1535CE3B396, 694, 228 }, +{ 0xFB9B7CD9A4A7443C, 720, 236 }, +{ 0xBB764C4CA7A44410, 747, 244 }, +{ 0x8BAB8EEFB6409C1A, 774, 252 }, +{ 0xD01FEF10A657842C, 800, 260 }, +{ 0x9B10A4E5E9913129, 827, 268 }, +{ 0xE7109BFBA19C0C9D, 853, 276 }, +{ 0xAC2820D9623BF429, 880, 284 }, +{ 0x80444B5E7AA7CF85, 907, 292 }, +{ 0xBF21E44003ACDD2D, 933, 300 }, +{ 0x8E679C2F5E44FF8F, 960, 308 }, +{ 0xD433179D9C8CB841, 986, 316 }, +{ 0x9E19DB92B4E31BA9, 1013, 324 }, +}; + +// This computation gives exactly the same results for k as +// k = ceil((kAlpha - e - 1) * 0.30102999566398114) +// for |e| <= 1500, but doesn't require floating-point operations. +// NB: log_10(2) ~= 78913 / 2^18 +assert(e >= -1500); +assert(e <= 1500); +const int f = kAlpha - e - 1; +const int k = (f * 78913) / (1 << 18) + (f > 0); + +const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; +assert(index >= 0); +assert(index < kCachedPowersSize); +static_cast(kCachedPowersSize); // Fix warning. + +const cached_power cached = kCachedPowers[index]; +assert(kAlpha <= cached.e + e + 64); +assert(kGamma >= cached.e + e + 64); + +return cached; +} + +/*! +For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k. +For n == 0, returns 1 and sets pow10 := 1. +*/ +inline int find_largest_pow10(const uint32_t n, uint32_t& pow10) +{ +// LCOV_EXCL_START +if (n >= 1000000000) +{ +pow10 = 1000000000; +return 10; +} +// LCOV_EXCL_STOP +else if (n >= 100000000) +{ +pow10 = 100000000; +return 9; +} +else if (n >= 10000000) +{ +pow10 = 10000000; +return 8; +} +else if (n >= 1000000) +{ +pow10 = 1000000; +return 7; +} +else if (n >= 100000) +{ +pow10 = 100000; +return 6; +} +else if (n >= 10000) +{ +pow10 = 10000; +return 5; +} +else if (n >= 1000) +{ +pow10 = 1000; +return 4; +} +else if (n >= 100) +{ +pow10 = 100; +return 3; +} +else if (n >= 10) +{ +pow10 = 10; +return 2; +} +else +{ +pow10 = 1; +return 1; +} +} + +inline void grisu2_round(char* buf, int len, uint64_t dist, uint64_t delta, +uint64_t rest, uint64_t ten_k) +{ +assert(len >= 1); +assert(dist <= delta); +assert(rest <= delta); +assert(ten_k > 0); + +// <--------------------------- delta ----> +// <---- dist ---------> +// --------------[------------------+-------------------]-------------- +// M- w M+ +// +// ten_k +// <------> +// <---- rest ----> +// --------------[------------------+----+--------------]-------------- +// w V +// = buf * 10^k +// +// ten_k represents a unit-in-the-last-place in the decimal representation +// stored in buf. +// Decrement buf by ten_k while this takes buf closer to w. + +// The tests are written in this order to avoid overflow in unsigned +// integer arithmetic. + +while (rest < dist +and delta - rest >= ten_k +and (rest + ten_k < dist or dist - rest > rest + ten_k - dist)) +{ +assert(buf[len - 1] != '0'); +buf[len - 1]--; +rest += ten_k; +} +} + +/*! +Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+. +M- and M+ must be normalized and share the same exponent -60 <= e <= -32. +*/ +inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, +diyfp M_minus, diyfp w, diyfp M_plus) +{ +static_assert(kAlpha >= -60, "internal error"); +static_assert(kGamma <= -32, "internal error"); + +// Generates the digits (and the exponent) of a decimal floating-point +// number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's +// w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma. +// +// <--------------------------- delta ----> +// <---- dist ---------> +// --------------[------------------+-------------------]-------------- +// M- w M+ +// +// Grisu2 generates the digits of M+ from left to right and stops as soon as +// V is in [M-,M+]. + +assert(M_plus.e >= kAlpha); +assert(M_plus.e <= kGamma); + +uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) +uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) + +// Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0): +// +// M+ = f * 2^e +// = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e +// = ((p1 ) * 2^-e + (p2 )) * 2^e +// = p1 + p2 * 2^e + +const diyfp one(uint64_t{1} << -M_plus.e, M_plus.e); + +uint32_t p1 = static_cast(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) +uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e + +// 1) +// +// Generate the digits of the integral part p1 = d[n-1]...d[1]d[0] + +assert(p1 > 0); + +uint32_t pow10; +const int k = find_largest_pow10(p1, pow10); + +// 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1) +// +// p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1)) +// = (d[k-1] ) * 10^(k-1) + (p1 mod 10^(k-1)) +// +// M+ = p1 + p2 * 2^e +// = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1)) + p2 * 2^e +// = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e +// = d[k-1] * 10^(k-1) + ( rest) * 2^e +// +// Now generate the digits d[n] of p1 from left to right (n = k-1,...,0) +// +// p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0] +// +// but stop as soon as +// +// rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e + +int n = k; +while (n > 0) +{ +// Invariants: +// M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k) +// pow10 = 10^(n-1) <= p1 < 10^n +// +const uint32_t d = p1 / pow10; // d = p1 div 10^(n-1) +const uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1) +// +// M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e +// = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) +// +assert(d <= 9); +buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d +// +// M+ = buffer * 10^(n-1) + (r + p2 * 2^e) +// +p1 = r; +n--; +// +// M+ = buffer * 10^n + (p1 + p2 * 2^e) +// pow10 = 10^n +// + +// Now check if enough digits have been generated. +// Compute +// +// p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e +// +// Note: +// Since rest and delta share the same exponent e, it suffices to +// compare the significands. +const uint64_t rest = (uint64_t{p1} << -one.e) + p2; +if (rest <= delta) +{ +// V = buffer * 10^n, with M- <= V <= M+. + +decimal_exponent += n; + +// We may now just stop. But instead look if the buffer could be +// decremented to bring V closer to w. +// +// pow10 = 10^n is now 1 ulp in the decimal representation V. +// The rounding procedure works with diyfp's with an implicit +// exponent of e. +// +// 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e +// +const uint64_t ten_n = uint64_t{pow10} << -one.e; +grisu2_round(buffer, length, dist, delta, rest, ten_n); + +return; +} + +pow10 /= 10; +// +// pow10 = 10^(n-1) <= p1 < 10^n +// Invariants restored. +} + +// 2) +// +// The digits of the integral part have been generated: +// +// M+ = d[k-1]...d[1]d[0] + p2 * 2^e +// = buffer + p2 * 2^e +// +// Now generate the digits of the fractional part p2 * 2^e. +// +// Note: +// No decimal point is generated: the exponent is adjusted instead. +// +// p2 actually represents the fraction +// +// p2 * 2^e +// = p2 / 2^-e +// = d[-1] / 10^1 + d[-2] / 10^2 + ... +// +// Now generate the digits d[-m] of p1 from left to right (m = 1,2,...) +// +// p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m +// + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...) +// +// using +// +// 10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e) +// = ( d) * 2^-e + ( r) +// +// or +// 10^m * p2 * 2^e = d + r * 2^e +// +// i.e. +// +// M+ = buffer + p2 * 2^e +// = buffer + 10^-m * (d + r * 2^e) +// = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e +// +// and stop as soon as 10^-m * r * 2^e <= delta * 2^e + +assert(p2 > delta); + +int m = 0; +for (;;) +{ +// Invariant: +// M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e +// = buffer * 10^-m + 10^-m * (p2 ) * 2^e +// = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e +// = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e +// +assert(p2 <= UINT64_MAX / 10); +p2 *= 10; +const uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e +const uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e +// +// M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e +// = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) +// = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e +// +assert(d <= 9); +buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d +// +// M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e +// +p2 = r; +m++; +// +// M+ = buffer * 10^-m + 10^-m * p2 * 2^e +// Invariant restored. + +// Check if enough digits have been generated. +// +// 10^-m * p2 * 2^e <= delta * 2^e +// p2 * 2^e <= 10^m * delta * 2^e +// p2 <= 10^m * delta +delta *= 10; +dist *= 10; +if (p2 <= delta) +{ +break; +} +} + +// V = buffer * 10^-m, with M- <= V <= M+. + +decimal_exponent -= m; + +// 1 ulp in the decimal representation is now 10^-m. +// Since delta and dist are now scaled by 10^m, we need to do the +// same with ulp in order to keep the units in sync. +// +// 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e +// +const uint64_t ten_m = one.f; +grisu2_round(buffer, length, dist, delta, p2, ten_m); + +// By construction this algorithm generates the shortest possible decimal +// number (Loitsch, Theorem 6.2) which rounds back to w. +// For an input number of precision p, at least +// +// N = 1 + ceil(p * log_10(2)) +// +// decimal digits are sufficient to identify all binary floating-point +// numbers (Matula, "In-and-Out conversions"). +// This implies that the algorithm does not produce more than N decimal +// digits. +// +// N = 17 for p = 53 (IEEE double precision) +// N = 9 for p = 24 (IEEE single precision) +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +inline void grisu2(char* buf, int& len, int& decimal_exponent, +diyfp m_minus, diyfp v, diyfp m_plus) +{ +assert(m_plus.e == m_minus.e); +assert(m_plus.e == v.e); + +// --------(-----------------------+-----------------------)-------- (A) +// m- v m+ +// +// --------------------(-----------+-----------------------)-------- (B) +// m- v m+ +// +// First scale v (and m- and m+) such that the exponent is in the range +// [alpha, gamma]. + +const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e); + +const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k + +// The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma] +const diyfp w = diyfp::mul(v, c_minus_k); +const diyfp w_minus = diyfp::mul(m_minus, c_minus_k); +const diyfp w_plus = diyfp::mul(m_plus, c_minus_k); + +// ----(---+---)---------------(---+---)---------------(---+---)---- +// w- w w+ +// = c*m- = c*v = c*m+ +// +// diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and +// w+ are now off by a small amount. +// In fact: +// +// w - v * 10^k < 1 ulp +// +// To account for this inaccuracy, add resp. subtract 1 ulp. +// +// --------+---[---------------(---+---)---------------]---+-------- +// w- M- w M+ w+ +// +// Now any number in [M-, M+] (bounds included) will round to w when input, +// regardless of how the input rounding algorithm breaks ties. +// +// And digit_gen generates the shortest possible such number in [M-, M+]. +// Note that this does not mean that Grisu2 always generates the shortest +// possible number in the interval (m-, m+). +const diyfp M_minus(w_minus.f + 1, w_minus.e); +const diyfp M_plus (w_plus.f - 1, w_plus.e ); + +decimal_exponent = -cached.k; // = -(-k) = k + +grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus); +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +template +void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value) +{ +static_assert(diyfp::kPrecision >= std::numeric_limits::digits + 3, +"internal error: not enough precision"); + +assert(std::isfinite(value)); +assert(value > 0); + +// If the neighbors (and boundaries) of 'value' are always computed for double-precision +// numbers, all float's can be recovered using strtod (and strtof). However, the resulting +// decimal representations are not exactly "short". +// +// The documentation for 'std::to_chars' (http://en.cppreference.com/w/cpp/utility/to_chars) +// says "value is converted to a string as if by std::sprintf in the default ("C") locale" +// and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars' +// does. +// On the other hand, the documentation for 'std::to_chars' requires that "parsing the +// representation using the corresponding std::from_chars function recovers value exactly". That +// indicates that single precision floating-point numbers should be recovered using +// 'std::strtof'. +// +// NB: If the neighbors are computed for single-precision numbers, there is a single float +// (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision +// value is off by 1 ulp. +#if 0 +const boundaries w = compute_boundaries(static_cast(value)); +#else +const boundaries w = compute_boundaries(value); +#endif + +grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus); +} + +/*! +@brief appends a decimal representation of e to buf +@return a pointer to the element following the exponent. +@pre -1000 < e < 1000 +*/ +inline char* append_exponent(char* buf, int e) +{ +assert(e > -1000); +assert(e < 1000); + +if (e < 0) +{ +e = -e; +*buf++ = '-'; +} +else +{ +*buf++ = '+'; +} + +uint32_t k = static_cast(e); +if (k < 10) +{ +// Always print at least two digits in the exponent. +// This is for compatibility with printf("%g"). +*buf++ = '0'; +*buf++ = static_cast('0' + k); +} +else if (k < 100) +{ +*buf++ = static_cast('0' + k / 10); +k %= 10; +*buf++ = static_cast('0' + k); +} +else +{ +*buf++ = static_cast('0' + k / 100); +k %= 100; +*buf++ = static_cast('0' + k / 10); +k %= 10; +*buf++ = static_cast('0' + k); +} + +return buf; +} + +/*! +@brief prettify v = buf * 10^decimal_exponent + +If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point +notation. Otherwise it will be printed in exponential notation. + +@pre min_exp < 0 +@pre max_exp > 0 +*/ +inline char* format_buffer(char* buf, int len, int decimal_exponent, +int min_exp, int max_exp) +{ +assert(min_exp < 0); +assert(max_exp > 0); + +const int k = len; +const int n = len + decimal_exponent; + +// v = buf * 10^(n-k) +// k is the length of the buffer (number of decimal digits) +// n is the position of the decimal point relative to the start of the buffer. + +if (k <= n and n <= max_exp) +{ +// digits[000] +// len <= max_exp + 2 + +std::memset(buf + k, '0', static_cast(n - k)); +// Make it look like a floating-point number (#362, #378) +buf[n + 0] = '.'; +buf[n + 1] = '0'; +return buf + (n + 2); +} + +if (0 < n and n <= max_exp) +{ +// dig.its +// len <= max_digits10 + 1 + +assert(k > n); + +std::memmove(buf + (n + 1), buf + n, static_cast(k - n)); +buf[n] = '.'; +return buf + (k + 1); +} + +if (min_exp < n and n <= 0) +{ +// 0.[000]digits +// len <= 2 + (-min_exp - 1) + max_digits10 + +std::memmove(buf + (2 + -n), buf, static_cast(k)); +buf[0] = '0'; +buf[1] = '.'; +std::memset(buf + 2, '0', static_cast(-n)); +return buf + (2 + (-n) + k); +} + +if (k == 1) +{ +// dE+123 +// len <= 1 + 5 + +buf += 1; +} +else +{ +// d.igitsE+123 +// len <= max_digits10 + 1 + 5 + +std::memmove(buf + 2, buf + 1, static_cast(k - 1)); +buf[1] = '.'; +buf += 1 + k; +} + +*buf++ = 'e'; +return append_exponent(buf, n - 1); +} + +} // namespace dtoa_impl + +/*! +@brief generates a decimal representation of the floating-point number value in [first, last). + +The format of the resulting decimal representation is similar to printf's %g +format. Returns an iterator pointing past-the-end of the decimal representation. + +@note The input number must be finite, i.e. NaN's and Inf's are not supported. +@note The buffer must be large enough. +@note The result is NOT null-terminated. +*/ +template +char* to_chars(char* first, char* last, FloatType value) +{ +static_cast(last); // maybe unused - fix warning +assert(std::isfinite(value)); + +// Use signbit(value) instead of (value < 0) since signbit works for -0. +if (std::signbit(value)) +{ +value = -value; +*first++ = '-'; +} + +if (value == 0) // +-0 +{ +*first++ = '0'; +// Make it look like a floating-point number (#362, #378) +*first++ = '.'; +*first++ = '0'; +return first; +} + +assert(last - first >= std::numeric_limits::max_digits10); + +// Compute v = buffer * 10^decimal_exponent. +// The decimal digits are stored in the buffer, which needs to be interpreted +// as an unsigned decimal integer. +// len is the length of the buffer, i.e. the number of decimal digits. +int len = 0; +int decimal_exponent = 0; +dtoa_impl::grisu2(first, len, decimal_exponent, value); + +assert(len <= std::numeric_limits::max_digits10); + +// Format the buffer like printf("%.*g", prec, value) +constexpr int kMinExp = -4; +// Use digits10 here to increase compatibility with version 2. +constexpr int kMaxExp = std::numeric_limits::digits10; + +assert(last - first >= kMaxExp + 2); +assert(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits::max_digits10); +assert(last - first >= std::numeric_limits::max_digits10 + 6); + +return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); +} + +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// serialization // +/////////////////// + +template +class serializer +{ +using string_t = typename BasicJsonType::string_t; +using number_float_t = typename BasicJsonType::number_float_t; +using number_integer_t = typename BasicJsonType::number_integer_t; +using number_unsigned_t = typename BasicJsonType::number_unsigned_t; +static constexpr uint8_t UTF8_ACCEPT = 0; +static constexpr uint8_t UTF8_REJECT = 1; + +public: +/*! + @param[in] s output stream to serialize to + @param[in] ichar indentation character to use + */ +serializer(output_adapter_t s, const char ichar) +: o(std::move(s)), loc(std::localeconv()), +thousands_sep(loc->thousands_sep == nullptr ? '\0' : * (loc->thousands_sep)), +decimal_point(loc->decimal_point == nullptr ? '\0' : * (loc->decimal_point)), +indent_char(ichar), indent_string(512, indent_char) +{} + +// delete because of pointer members +serializer(const serializer&) = delete; +serializer& operator=(const serializer&) = delete; + +/*! + @brief internal implementation of the serialization function + + This function is called by the public member function dump and organizes + the serialization internally. The indentation level is propagated as + additional parameter. In case of arrays and objects, the function is + called recursively. + + - strings and object keys are escaped using `escape_string()` + - integer numbers are converted implicitly via `operator<<` + - floating-point numbers are converted to a string using `"%g"` format + + @param[in] val value to serialize + @param[in] pretty_print whether the output shall be pretty-printed + @param[in] indent_step the indent level + @param[in] current_indent the current indent level (only used internally) + */ +void dump(const BasicJsonType& val, const bool pretty_print, +const bool ensure_ascii, +const unsigned int indent_step, +const unsigned int current_indent = 0) +{ +switch (val.m_type) +{ +case value_t::object: +{ +if (val.m_value.object->empty()) +{ +o->write_characters("{}", 2); +return; +} + +if (pretty_print) +{ +o->write_characters("{\n", 2); + +// variable to hold indentation for recursive calls +const auto new_indent = current_indent + indent_step; +if (JSON_UNLIKELY(indent_string.size() < new_indent)) +{ +indent_string.resize(indent_string.size() * 2, ' '); +} + +// first n-1 elements +auto i = val.m_value.object->cbegin(); +for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) +{ +o->write_characters(indent_string.c_str(), new_indent); +o->write_character('\"'); +dump_escaped(i->first, ensure_ascii); +o->write_characters("\": ", 3); +dump(i->second, true, ensure_ascii, indent_step, new_indent); +o->write_characters(",\n", 2); +} + +// last element +assert(i != val.m_value.object->cend()); +assert(std::next(i) == val.m_value.object->cend()); +o->write_characters(indent_string.c_str(), new_indent); +o->write_character('\"'); +dump_escaped(i->first, ensure_ascii); +o->write_characters("\": ", 3); +dump(i->second, true, ensure_ascii, indent_step, new_indent); + +o->write_character('\n'); +o->write_characters(indent_string.c_str(), current_indent); +o->write_character('}'); +} +else +{ +o->write_character('{'); + +// first n-1 elements +auto i = val.m_value.object->cbegin(); +for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) +{ +o->write_character('\"'); +dump_escaped(i->first, ensure_ascii); +o->write_characters("\":", 2); +dump(i->second, false, ensure_ascii, indent_step, current_indent); +o->write_character(','); +} + +// last element +assert(i != val.m_value.object->cend()); +assert(std::next(i) == val.m_value.object->cend()); +o->write_character('\"'); +dump_escaped(i->first, ensure_ascii); +o->write_characters("\":", 2); +dump(i->second, false, ensure_ascii, indent_step, current_indent); + +o->write_character('}'); +} + +return; +} + +case value_t::array: +{ +if (val.m_value.array->empty()) +{ +o->write_characters("[]", 2); +return; +} + +if (pretty_print) +{ +o->write_characters("[\n", 2); + +// variable to hold indentation for recursive calls +const auto new_indent = current_indent + indent_step; +if (JSON_UNLIKELY(indent_string.size() < new_indent)) +{ +indent_string.resize(indent_string.size() * 2, ' '); +} + +// first n-1 elements +for (auto i = val.m_value.array->cbegin(); +i != val.m_value.array->cend() - 1; ++i) +{ +o->write_characters(indent_string.c_str(), new_indent); +dump(*i, true, ensure_ascii, indent_step, new_indent); +o->write_characters(",\n", 2); +} + +// last element +assert(not val.m_value.array->empty()); +o->write_characters(indent_string.c_str(), new_indent); +dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); + +o->write_character('\n'); +o->write_characters(indent_string.c_str(), current_indent); +o->write_character(']'); +} +else +{ +o->write_character('['); + +// first n-1 elements +for (auto i = val.m_value.array->cbegin(); +i != val.m_value.array->cend() - 1; ++i) +{ +dump(*i, false, ensure_ascii, indent_step, current_indent); +o->write_character(','); +} + +// last element +assert(not val.m_value.array->empty()); +dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); + +o->write_character(']'); +} + +return; +} + +case value_t::string: +{ +o->write_character('\"'); +dump_escaped(*val.m_value.string, ensure_ascii); +o->write_character('\"'); +return; +} + +case value_t::boolean: +{ +if (val.m_value.boolean) +{ +o->write_characters("true", 4); +} +else +{ +o->write_characters("false", 5); +} +return; +} + +case value_t::number_integer: +{ +dump_integer(val.m_value.number_integer); +return; +} + +case value_t::number_unsigned: +{ +dump_integer(val.m_value.number_unsigned); +return; +} + +case value_t::number_float: +{ +dump_float(val.m_value.number_float); +return; +} + +case value_t::discarded: +{ +o->write_characters("", 11); +return; +} + +case value_t::null: +{ +o->write_characters("null", 4); +return; +} +} +} + +private: +/*! + @brief dump escaped string + + Escape a string by replacing certain special characters by a sequence of an + escape character (backslash) and another character and other control + characters by a sequence of "\u" followed by a four-digit hex + representation. The escaped string is written to output stream @a o. + + @param[in] s the string to escape + @param[in] ensure_ascii whether to escape non-ASCII characters with + \uXXXX sequences + + @complexity Linear in the length of string @a s. + */ +void dump_escaped(const string_t& s, const bool ensure_ascii) +{ +uint32_t codepoint; +uint8_t state = UTF8_ACCEPT; +std::size_t bytes = 0; // number of bytes written to string_buffer + +for (std::size_t i = 0; i < s.size(); ++i) +{ +const auto byte = static_cast(s[i]); + +switch (decode(state, codepoint, byte)) +{ +case UTF8_ACCEPT: // decode found a new code point +{ +switch (codepoint) +{ +case 0x08: // backspace +{ +string_buffer[bytes++] = '\\'; +string_buffer[bytes++] = 'b'; +break; +} + +case 0x09: // horizontal tab +{ +string_buffer[bytes++] = '\\'; +string_buffer[bytes++] = 't'; +break; +} + +case 0x0A: // newline +{ +string_buffer[bytes++] = '\\'; +string_buffer[bytes++] = 'n'; +break; +} + +case 0x0C: // formfeed +{ +string_buffer[bytes++] = '\\'; +string_buffer[bytes++] = 'f'; +break; +} + +case 0x0D: // carriage return +{ +string_buffer[bytes++] = '\\'; +string_buffer[bytes++] = 'r'; +break; +} + +case 0x22: // quotation mark +{ +string_buffer[bytes++] = '\\'; +string_buffer[bytes++] = '\"'; +break; +} + +case 0x5C: // reverse solidus +{ +string_buffer[bytes++] = '\\'; +string_buffer[bytes++] = '\\'; +break; +} + +default: +{ +// escape control characters (0x00..0x1F) or, if +// ensure_ascii parameter is used, non-ASCII characters +if ((codepoint <= 0x1F) or (ensure_ascii and (codepoint >= 0x7F))) +{ +if (codepoint <= 0xFFFF) +{ +std::snprintf(string_buffer.data() + bytes, 7, "\\u%04x", +static_cast(codepoint)); +bytes += 6; +} +else +{ +std::snprintf(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", +static_cast(0xD7C0 + (codepoint >> 10)), +static_cast(0xDC00 + (codepoint & 0x3FF))); +bytes += 12; +} +} +else +{ +// copy byte to buffer (all previous bytes +// been copied have in default case above) +string_buffer[bytes++] = s[i]; +} +break; +} +} + +// write buffer and reset index; there must be 13 bytes +// left, as this is the maximal number of bytes to be +// written ("\uxxxx\uxxxx\0") for one code point +if (string_buffer.size() - bytes < 13) +{ +o->write_characters(string_buffer.data(), bytes); +bytes = 0; +} +break; +} + +case UTF8_REJECT: // decode found invalid UTF-8 byte +{ +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(byte); +JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + ss.str())); +} + +default: // decode found yet incomplete multi-byte code point +{ +if (not ensure_ascii) +{ +// code point will not be escaped - copy byte to buffer +string_buffer[bytes++] = s[i]; +} +break; +} +} +} + +if (JSON_LIKELY(state == UTF8_ACCEPT)) +{ +// write buffer +if (bytes > 0) +{ +o->write_characters(string_buffer.data(), bytes); +} +} +else +{ +// we finish reading, but do not accept: string was incomplete +std::stringstream ss; +ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(static_cast(s.back())); +JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + ss.str())); +} +} + +/*! + @brief dump an integer + + Dump a given integer to output stream @a o. Works internally with + @a number_buffer. + + @param[in] x integer number (signed or unsigned) to dump + @tparam NumberType either @a number_integer_t or @a number_unsigned_t + */ +template::value or +std::is_same::value, +int> = 0> +void dump_integer(NumberType x) +{ +// special case for "0" +if (x == 0) +{ +o->write_character('0'); +return; +} + +const bool is_negative = (x <= 0) and (x != 0); // see issue #755 +std::size_t i = 0; + +while (x != 0) +{ +// spare 1 byte for '\0' +assert(i < number_buffer.size() - 1); + +const auto digit = std::labs(static_cast(x % 10)); +number_buffer[i++] = static_cast('0' + digit); +x /= 10; +} + +if (is_negative) +{ +// make sure there is capacity for the '-' +assert(i < number_buffer.size() - 2); +number_buffer[i++] = '-'; +} + +std::reverse(number_buffer.begin(), number_buffer.begin() + i); +o->write_characters(number_buffer.data(), i); +} + +/*! + @brief dump a floating-point number + + Dump a given floating-point number to output stream @a o. Works internally + with @a number_buffer. + + @param[in] x floating-point number to dump + */ +void dump_float(number_float_t x) +{ +// NaN / inf +if (not std::isfinite(x)) +{ +o->write_characters("null", 4); +return; +} + +// If number_float_t is an IEEE-754 single or double precision number, +// use the Grisu2 algorithm to produce short numbers which are +// guaranteed to round-trip, using strtof and strtod, resp. +// +// NB: The test below works if == . +static constexpr bool is_ieee_single_or_double += (std::numeric_limits::is_iec559 and std::numeric_limits::digits == 24 and std::numeric_limits::max_exponent == 128) or +(std::numeric_limits::is_iec559 and std::numeric_limits::digits == 53 and std::numeric_limits::max_exponent == 1024); + +dump_float(x, std::integral_constant()); +} + +void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/) +{ +char* begin = number_buffer.data(); +char* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x); + +o->write_characters(begin, static_cast(end - begin)); +} + +void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/) +{ +// get number of digits for a float -> text -> float round-trip +static constexpr auto d = std::numeric_limits::max_digits10; + +// the actual conversion +std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(), "%.*g", d, x); + +// negative value indicates an error +assert(len > 0); +// check if buffer was large enough +assert(static_cast(len) < number_buffer.size()); + +// erase thousands separator +if (thousands_sep != '\0') +{ +const auto end = std::remove(number_buffer.begin(), +number_buffer.begin() + len, thousands_sep); +std::fill(end, number_buffer.end(), '\0'); +assert((end - number_buffer.begin()) <= len); +len = (end - number_buffer.begin()); +} + +// convert decimal point to '.' +if (decimal_point != '\0' and decimal_point != '.') +{ +const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); +if (dec_pos != number_buffer.end()) +{ +*dec_pos = '.'; +} +} + +o->write_characters(number_buffer.data(), static_cast(len)); + +// determine if need to append ".0" +const bool value_is_int_like = +std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, +[](char c) +{ +return (c == '.' or c == 'e'); +}); + +if (value_is_int_like) +{ +o->write_characters(".0", 2); +} +} + +/*! + @brief check whether a string is UTF-8 encoded + + The function checks each byte of a string whether it is UTF-8 encoded. The + result of the check is stored in the @a state parameter. The function must + be called initially with state 0 (accept). State 1 means the string must + be rejected, because the current byte is not allowed. If the string is + completely processed, but the state is non-zero, the string ended + prematurely; that is, the last byte indicated more bytes should have + followed. + + @param[in,out] state the state of the decoding + @param[in,out] codep codepoint (valid only if resulting state is UTF8_ACCEPT) + @param[in] byte next byte to decode + @return new state + + @note The function has been edited: a std::array is used. + + @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann + @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ + */ +static uint8_t decode(uint8_t& state, uint32_t& codep, const uint8_t byte) noexcept +{ +static const std::array utf8d = +{ +{ +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF +8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF +0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF +0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF +0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 +1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 +1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 +1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 +} +}; + +const uint8_t type = utf8d[byte]; + +codep = (state != UTF8_ACCEPT) +? (byte & 0x3fu) | (codep << 6) +: static_cast(0xff >> type) & (byte); + +state = utf8d[256u + state * 16u + type]; +return state; +} + +private: +/// the output of the serializer +output_adapter_t o = nullptr; + +/// a (hopefully) large enough character buffer +std::array number_buffer{{}}; + +/// the locale +const std::lconv* loc = nullptr; +/// the locale's thousand separator character +const char thousands_sep = '\0'; +/// the locale's decimal point character +const char decimal_point = '\0'; + +/// string buffer +std::array string_buffer{{}}; + +/// the indentation character +const char indent_char; +/// the indentation string +string_t indent_string; +}; +} +} + +// #include + + +#include +#include + +namespace nlohmann +{ +namespace detail +{ +template +class json_ref +{ +public: +using value_type = BasicJsonType; + +json_ref(value_type&& value) +: owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true) +{} + +json_ref(const value_type& value) +: value_ref(const_cast(&value)), is_rvalue(false) +{} + +json_ref(std::initializer_list init) +: owned_value(init), value_ref(&owned_value), is_rvalue(true) +{} + +template +json_ref(Args&& ... args) +: owned_value(std::forward(args)...), value_ref(&owned_value), is_rvalue(true) +{} + +// class should be movable only +json_ref(json_ref&&) = default; +json_ref(const json_ref&) = delete; +json_ref& operator=(const json_ref&) = delete; + +value_type moved_or_copied() const +{ +if (is_rvalue) +{ +return std::move(*value_ref); +} +return *value_ref; +} + +value_type const& operator*() const +{ +return *static_cast(value_ref); +} + +value_type const* operator->() const +{ +return static_cast(value_ref); +} + +private: +mutable value_type owned_value = nullptr; +value_type* value_ref = nullptr; +const bool is_rvalue; +}; +} +} + +// #include + + +#include // assert +#include // accumulate +#include // string +#include // vector + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +template +class json_pointer +{ +// allow basic_json to access private members +NLOHMANN_BASIC_JSON_TPL_DECLARATION +friend class basic_json; + +public: +/*! + @brief create JSON pointer + + Create a JSON pointer according to the syntax described in + [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). + + @param[in] s string representing the JSON pointer; if omitted, the empty + string is assumed which references the whole JSON value + + @throw parse_error.107 if the given JSON pointer @a s is nonempty and does + not begin with a slash (`/`); see example below + + @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s is + not followed by `0` (representing `~`) or `1` (representing `/`); see + example below + + @liveexample{The example shows the construction several valid JSON pointers + as well as the exceptional behavior.,json_pointer} + + @since version 2.0.0 + */ +explicit json_pointer(const std::string& s = "") +: reference_tokens(split(s)) +{} + +/*! + @brief return a string representation of the JSON pointer + + @invariant For each JSON pointer `ptr`, it holds: + @code {.cpp} + ptr == json_pointer(ptr.to_string()); + @endcode + + @return a string representation of the JSON pointer + + @liveexample{The example shows the result of `to_string`., + json_pointer__to_string} + + @since version 2.0.0 + */ +std::string to_string() const noexcept +{ +return std::accumulate(reference_tokens.begin(), reference_tokens.end(), +std::string{}, +[](const std::string & a, const std::string & b) +{ +return a + "/" + escape(b); +}); +} + +/// @copydoc to_string() +operator std::string() const +{ +return to_string(); +} + +/*! + @param[in] s reference token to be converted into an array index + + @return integer representation of @a s + + @throw out_of_range.404 if string @a s could not be converted to an integer + */ +static int array_index(const std::string& s) +{ +std::size_t processed_chars = 0; +const int res = std::stoi(s, &processed_chars); + +// check if the string was completely read +if (JSON_UNLIKELY(processed_chars != s.size())) +{ +JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); +} + +return res; +} + +private: +/*! + @brief remove and return last reference pointer + @throw out_of_range.405 if JSON pointer has no parent + */ +std::string pop_back() +{ +if (JSON_UNLIKELY(is_root())) +{ +JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); +} + +auto last = reference_tokens.back(); +reference_tokens.pop_back(); +return last; +} + +/// return whether pointer points to the root document +bool is_root() const +{ +return reference_tokens.empty(); +} + +json_pointer top() const +{ +if (JSON_UNLIKELY(is_root())) +{ +JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); +} + +json_pointer result = *this; +result.reference_tokens = {reference_tokens[0]}; +return result; +} + +/*! + @brief create and return a reference to the pointed to value + + @complexity Linear in the number of reference tokens. + + @throw parse_error.109 if array index is not a number + @throw type_error.313 if value cannot be unflattened + */ +BasicJsonType& get_and_create(BasicJsonType& j) const +{ +using size_type = typename BasicJsonType::size_type; +auto result = &j; + +// in case no reference tokens exist, return a reference to the JSON value +// j which will be overwritten by a primitive value +for (const auto& reference_token : reference_tokens) +{ +switch (result->m_type) +{ +case detail::value_t::null: +{ +if (reference_token == "0") +{ +// start a new array if reference token is 0 +result = &result->operator[](0); +} +else +{ +// start a new object otherwise +result = &result->operator[](reference_token); +} +break; +} + +case detail::value_t::object: +{ +// create an entry in the object +result = &result->operator[](reference_token); +break; +} + +case detail::value_t::array: +{ +// create an entry in the array +JSON_TRY +{ +result = &result->operator[](static_cast(array_index(reference_token))); +} +JSON_CATCH(std::invalid_argument&) +{ +JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); +} +break; +} + +/* + The following code is only reached if there exists a reference + token _and_ the current value is primitive. In this case, we have + an error situation, because primitive values may only occur as + single value; that is, with an empty list of reference tokens. + */ +default: +JSON_THROW(detail::type_error::create(313, "invalid value to unflatten")); +} +} + +return *result; +} + +/*! + @brief return a reference to the pointed to value + + @note This version does not throw if a value is not present, but tries to + create nested values instead. For instance, calling this function + with pointer `"/this/that"` on a null value is equivalent to calling + `operator[]("this").operator[]("that")` on that value, effectively + changing the null value to an object. + + @param[in] ptr a JSON value + + @return reference to the JSON value pointed to by the JSON pointer + + @complexity Linear in the length of the JSON pointer. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + */ +BasicJsonType& get_unchecked(BasicJsonType* ptr) const +{ +using size_type = typename BasicJsonType::size_type; +for (const auto& reference_token : reference_tokens) +{ +// convert null values to arrays or objects before continuing +if (ptr->m_type == detail::value_t::null) +{ +// check if reference token is a number +const bool nums = +std::all_of(reference_token.begin(), reference_token.end(), +[](const char x) +{ +return (x >= '0' and x <= '9'); +}); + +// change value to array for numbers or "-" or to object otherwise +*ptr = (nums or reference_token == "-") +? detail::value_t::array +: detail::value_t::object; +} + +switch (ptr->m_type) +{ +case detail::value_t::object: +{ +// use unchecked object access +ptr = &ptr->operator[](reference_token); +break; +} + +case detail::value_t::array: +{ +// error condition (cf. RFC 6901, Sect. 4) +if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) +{ +JSON_THROW(detail::parse_error::create(106, 0, +"array index '" + reference_token + +"' must not begin with '0'")); +} + +if (reference_token == "-") +{ +// explicitly treat "-" as index beyond the end +ptr = &ptr->operator[](ptr->m_value.array->size()); +} +else +{ +// convert array index to number; unchecked access +JSON_TRY +{ +ptr = &ptr->operator[]( +static_cast(array_index(reference_token))); +} +JSON_CATCH(std::invalid_argument&) +{ +JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); +} +} +break; +} + +default: +JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); +} +} + +return *ptr; +} + +/*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ +BasicJsonType& get_checked(BasicJsonType* ptr) const +{ +using size_type = typename BasicJsonType::size_type; +for (const auto& reference_token : reference_tokens) +{ +switch (ptr->m_type) +{ +case detail::value_t::object: +{ +// note: at performs range check +ptr = &ptr->at(reference_token); +break; +} + +case detail::value_t::array: +{ +if (JSON_UNLIKELY(reference_token == "-")) +{ +// "-" always fails the range check +JSON_THROW(detail::out_of_range::create(402, +"array index '-' (" + std::to_string(ptr->m_value.array->size()) + +") is out of range")); +} + +// error condition (cf. RFC 6901, Sect. 4) +if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) +{ +JSON_THROW(detail::parse_error::create(106, 0, +"array index '" + reference_token + +"' must not begin with '0'")); +} + +// note: at performs range check +JSON_TRY +{ +ptr = &ptr->at(static_cast(array_index(reference_token))); +} +JSON_CATCH(std::invalid_argument&) +{ +JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); +} +break; +} + +default: +JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); +} +} + +return *ptr; +} + +/*! + @brief return a const reference to the pointed to value + + @param[in] ptr a JSON value + + @return const reference to the JSON value pointed to by the JSON + pointer + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ +const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const +{ +using size_type = typename BasicJsonType::size_type; +for (const auto& reference_token : reference_tokens) +{ +switch (ptr->m_type) +{ +case detail::value_t::object: +{ +// use unchecked object access +ptr = &ptr->operator[](reference_token); +break; +} + +case detail::value_t::array: +{ +if (JSON_UNLIKELY(reference_token == "-")) +{ +// "-" cannot be used for const access +JSON_THROW(detail::out_of_range::create(402, +"array index '-' (" + std::to_string(ptr->m_value.array->size()) + +") is out of range")); +} + +// error condition (cf. RFC 6901, Sect. 4) +if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) +{ +JSON_THROW(detail::parse_error::create(106, 0, +"array index '" + reference_token + +"' must not begin with '0'")); +} + +// use unchecked array access +JSON_TRY +{ +ptr = &ptr->operator[]( +static_cast(array_index(reference_token))); +} +JSON_CATCH(std::invalid_argument&) +{ +JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); +} +break; +} + +default: +JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); +} +} + +return *ptr; +} + +/*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ +const BasicJsonType& get_checked(const BasicJsonType* ptr) const +{ +using size_type = typename BasicJsonType::size_type; +for (const auto& reference_token : reference_tokens) +{ +switch (ptr->m_type) +{ +case detail::value_t::object: +{ +// note: at performs range check +ptr = &ptr->at(reference_token); +break; +} + +case detail::value_t::array: +{ +if (JSON_UNLIKELY(reference_token == "-")) +{ +// "-" always fails the range check +JSON_THROW(detail::out_of_range::create(402, +"array index '-' (" + std::to_string(ptr->m_value.array->size()) + +") is out of range")); +} + +// error condition (cf. RFC 6901, Sect. 4) +if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0')) +{ +JSON_THROW(detail::parse_error::create(106, 0, +"array index '" + reference_token + +"' must not begin with '0'")); +} + +// note: at performs range check +JSON_TRY +{ +ptr = &ptr->at(static_cast(array_index(reference_token))); +} +JSON_CATCH(std::invalid_argument&) +{ +JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); +} +break; +} + +default: +JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); +} +} + +return *ptr; +} + +/*! + @brief split the string input to reference tokens + + @note This function is only called by the json_pointer constructor. + All exceptions below are documented there. + + @throw parse_error.107 if the pointer is not empty or begins with '/' + @throw parse_error.108 if character '~' is not followed by '0' or '1' + */ +static std::vector split(const std::string& reference_string) +{ +std::vector result; + +// special case: empty reference string -> no reference tokens +if (reference_string.empty()) +{ +return result; +} + +// check if nonempty reference string begins with slash +if (JSON_UNLIKELY(reference_string[0] != '/')) +{ +JSON_THROW(detail::parse_error::create(107, 1, +"JSON pointer must be empty or begin with '/' - was: '" + +reference_string + "'")); +} + +// extract the reference tokens: +// - slash: position of the last read slash (or end of string) +// - start: position after the previous slash +for ( +// search for the first slash after the first character +std::size_t slash = reference_string.find_first_of('/', 1), +// set the beginning of the first reference token +start = 1; +// we can stop if start == string::npos+1 = 0 +start != 0; +// set the beginning of the next reference token +// (will eventually be 0 if slash == std::string::npos) +start = slash + 1, +// find next slash +slash = reference_string.find_first_of('/', start)) +{ +// use the text between the beginning of the reference token +// (start) and the last slash (slash). +auto reference_token = reference_string.substr(start, slash - start); + +// check reference tokens are properly escaped +for (std::size_t pos = reference_token.find_first_of('~'); +pos != std::string::npos; +pos = reference_token.find_first_of('~', pos + 1)) +{ +assert(reference_token[pos] == '~'); + +// ~ must be followed by 0 or 1 +if (JSON_UNLIKELY(pos == reference_token.size() - 1 or +(reference_token[pos + 1] != '0' and +reference_token[pos + 1] != '1'))) +{ +JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'")); +} +} + +// finally, store the reference token +unescape(reference_token); +result.push_back(reference_token); +} + +return result; +} + +/*! + @brief replace all occurrences of a substring by another string + + @param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t + @param[in] f the substring to replace with @a t + @param[in] t the string to replace @a f + + @pre The search string @a f must not be empty. **This precondition is + enforced with an assertion.** + + @since version 2.0.0 + */ +static void replace_substring(std::string& s, const std::string& f, +const std::string& t) +{ +assert(not f.empty()); +for (auto pos = s.find(f); // find first occurrence of f +pos != std::string::npos; // make sure f was found +s.replace(pos, f.size(), t), // replace with t, and +pos = s.find(f, pos + t.size())) // find next occurrence of f +{} +} + +/// escape "~"" to "~0" and "/" to "~1" +static std::string escape(std::string s) +{ +replace_substring(s, "~", "~0"); +replace_substring(s, "/", "~1"); +return s; +} + +/// unescape "~1" to tilde and "~0" to slash (order is important!) +static void unescape(std::string& s) +{ +replace_substring(s, "~1", "/"); +replace_substring(s, "~0", "~"); +} + +/*! + @param[in] reference_string the reference string to the current value + @param[in] value the value to consider + @param[in,out] result the result object to insert values to + + @note Empty objects or arrays are flattened to `null`. + */ +static void flatten(const std::string& reference_string, +const BasicJsonType& value, +BasicJsonType& result) +{ +switch (value.m_type) +{ +case detail::value_t::array: +{ +if (value.m_value.array->empty()) +{ +// flatten empty array as null +result[reference_string] = nullptr; +} +else +{ +// iterate array and use index as reference string +for (std::size_t i = 0; i < value.m_value.array->size(); ++i) +{ +flatten(reference_string + "/" + std::to_string(i), +value.m_value.array->operator[](i), result); +} +} +break; +} + +case detail::value_t::object: +{ +if (value.m_value.object->empty()) +{ +// flatten empty object as null +result[reference_string] = nullptr; +} +else +{ +// iterate object and use keys as reference string +for (const auto& element : *value.m_value.object) +{ +flatten(reference_string + "/" + escape(element.first), element.second, result); +} +} +break; +} + +default: +{ +// add primitive value with its reference string +result[reference_string] = value; +break; +} +} +} + +/*! + @param[in] value flattened JSON + + @return unflattened JSON + + @throw parse_error.109 if array index is not a number + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + @throw type_error.313 if value cannot be unflattened + */ +static BasicJsonType +unflatten(const BasicJsonType& value) +{ +if (JSON_UNLIKELY(not value.is_object())) +{ +JSON_THROW(detail::type_error::create(314, "only objects can be unflattened")); +} + +BasicJsonType result; + +// iterate the JSON object values +for (const auto& element : *value.m_value.object) +{ +if (JSON_UNLIKELY(not element.second.is_primitive())) +{ +JSON_THROW(detail::type_error::create(315, "values in object must be primitive")); +} + +// assign value to reference pointed to by JSON pointer; Note that if +// the JSON pointer is "" (i.e., points to the whole value), function +// get_and_create returns a reference to result itself. An assignment +// will then create a primitive value. +json_pointer(element.first).get_and_create(result) = element.second; +} + +return result; +} + +friend bool operator==(json_pointer const& lhs, +json_pointer const& rhs) noexcept +{ +return (lhs.reference_tokens == rhs.reference_tokens); +} + +friend bool operator!=(json_pointer const& lhs, +json_pointer const& rhs) noexcept +{ +return not (lhs == rhs); +} + +/// the reference tokens +std::vector reference_tokens; +}; +} + +// #include + + +#include + +// #include + +// #include + + +namespace nlohmann +{ +template +struct adl_serializer +{ +/*! + @brief convert a JSON value to any value type + + This function is usually called by the `get()` function of the + @ref basic_json class (either explicit or via conversion operators). + + @param[in] j JSON value to read from + @param[in,out] val value to write to + */ +template +static void from_json(BasicJsonType&& j, ValueType& val) noexcept( +noexcept(::nlohmann::from_json(std::forward(j), val))) +{ +::nlohmann::from_json(std::forward(j), val); +} + +/*! + @brief convert any value type to a JSON value + + This function is usually called by the constructors of the @ref basic_json + class. + + @param[in,out] j JSON value to write to + @param[in] val value to read from + */ +template +static void to_json(BasicJsonType& j, ValueType&& val) noexcept( +noexcept(::nlohmann::to_json(j, std::forward(val)))) +{ +::nlohmann::to_json(j, std::forward(val)); +} +}; +} + + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ + +/*! +@brief a class to store JSON values + +@tparam ObjectType type for JSON objects (`std::map` by default; will be used +in @ref object_t) +@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used +in @ref array_t) +@tparam StringType type for JSON strings and object keys (`std::string` by +default; will be used in @ref string_t) +@tparam BooleanType type for JSON booleans (`bool` by default; will be used +in @ref boolean_t) +@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by +default; will be used in @ref number_integer_t) +@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c +`uint64_t` by default; will be used in @ref number_unsigned_t) +@tparam NumberFloatType type for JSON floating-point numbers (`double` by +default; will be used in @ref number_float_t) +@tparam AllocatorType type of the allocator to use (`std::allocator` by +default) +@tparam JSONSerializer the serializer to resolve internal calls to `to_json()` +and `from_json()` (@ref adl_serializer by default) + +@requirement The class satisfies the following concept requirements: +- Basic + - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): + JSON values can be default constructed. The result will be a JSON null + value. + - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): + A JSON value can be constructed from an rvalue argument. + - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): + A JSON value can be copy-constructed from an lvalue expression. + - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): + A JSON value van be assigned from an rvalue argument. + - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): + A JSON value can be copy-assigned from an lvalue expression. + - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible): + JSON values can be destructed. +- Layout + - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType): + JSON values have + [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout): + All non-static data members are private and standard layout types, the + class has no virtual functions or (virtual) base classes. +- Library-wide + - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable): + JSON values can be compared with `==`, see @ref + operator==(const_reference,const_reference). + - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable): + JSON values can be compared with `<`, see @ref + operator<(const_reference,const_reference). + - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable): + Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of + other compatible types, using unqualified function call @ref swap(). + - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer): + JSON values can be compared against `std::nullptr_t` objects which are used + to model the `null` value. +- Container + - [Container](http://en.cppreference.com/w/cpp/concept/Container): + JSON values can be used like STL containers and provide iterator access. + - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer); + JSON values can be used like STL containers and provide reverse iterator + access. + +@invariant The member variables @a m_value and @a m_type have the following +relationship: +- If `m_type == value_t::object`, then `m_value.object != nullptr`. +- If `m_type == value_t::array`, then `m_value.array != nullptr`. +- If `m_type == value_t::string`, then `m_value.string != nullptr`. +The invariants are checked by member function assert_invariant(). + +@internal +@note ObjectType trick from http://stackoverflow.com/a/9860911 +@endinternal + +@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange +Format](http://rfc7159.net/rfc7159) + +@since version 1.0.0 + +@nosubgrouping +*/ +NLOHMANN_BASIC_JSON_TPL_DECLARATION +class basic_json +{ +private: +template friend struct detail::external_constructor; +friend ::nlohmann::json_pointer; +friend ::nlohmann::detail::parser; +friend ::nlohmann::detail::serializer; +template +friend class ::nlohmann::detail::iter_impl; +template +friend class ::nlohmann::detail::binary_writer; +template +friend class ::nlohmann::detail::binary_reader; + +/// workaround type for MSVC +using basic_json_t = NLOHMANN_BASIC_JSON_TPL; + +// convenience aliases for types residing in namespace detail; +using lexer = ::nlohmann::detail::lexer; +using parser = ::nlohmann::detail::parser; + +using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t; +template +using internal_iterator = ::nlohmann::detail::internal_iterator; +template +using iter_impl = ::nlohmann::detail::iter_impl; +template +using iteration_proxy = ::nlohmann::detail::iteration_proxy; +template using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator; + +template +using output_adapter_t = ::nlohmann::detail::output_adapter_t; + +using binary_reader = ::nlohmann::detail::binary_reader; +template using binary_writer = ::nlohmann::detail::binary_writer; + +using serializer = ::nlohmann::detail::serializer; + +public: +using value_t = detail::value_t; +/// @copydoc nlohmann::json_pointer +using json_pointer = ::nlohmann::json_pointer; +template +using json_serializer = JSONSerializer; +/// helper type for initializer lists of basic_json values +using initializer_list_t = std::initializer_list>; + +//////////////// +// exceptions // +//////////////// + +/// @name exceptions +/// Classes to implement user-defined exceptions. +/// @{ + +/// @copydoc detail::exception +using exception = detail::exception; +/// @copydoc detail::parse_error +using parse_error = detail::parse_error; +/// @copydoc detail::invalid_iterator +using invalid_iterator = detail::invalid_iterator; +/// @copydoc detail::type_error +using type_error = detail::type_error; +/// @copydoc detail::out_of_range +using out_of_range = detail::out_of_range; +/// @copydoc detail::other_error +using other_error = detail::other_error; + +/// @} + + +///////////////////// +// container types // +///////////////////// + +/// @name container types +/// The canonic container types to use @ref basic_json like any other STL +/// container. +/// @{ + +/// the type of elements in a basic_json container +using value_type = basic_json; + +/// the type of an element reference +using reference = value_type&; +/// the type of an element const reference +using const_reference = const value_type&; + +/// a type to represent differences between iterators +using difference_type = std::ptrdiff_t; +/// a type to represent container sizes +using size_type = std::size_t; + +/// the allocator type +using allocator_type = AllocatorType; + +/// the type of an element pointer +using pointer = typename std::allocator_traits::pointer; +/// the type of an element const pointer +using const_pointer = typename std::allocator_traits::const_pointer; + +/// an iterator for a basic_json container +using iterator = iter_impl; +/// a const iterator for a basic_json container +using const_iterator = iter_impl; +/// a reverse iterator for a basic_json container +using reverse_iterator = json_reverse_iterator; +/// a const reverse iterator for a basic_json container +using const_reverse_iterator = json_reverse_iterator; + +/// @} + + +/*! + @brief returns the allocator associated with the container + */ +static allocator_type get_allocator() +{ +return allocator_type(); +} + +/*! + @brief returns version information on the library + + This function returns a JSON object with information about the library, + including the version number and information on the platform and compiler. + + @return JSON object holding version information + key | description + ----------- | --------------- + `compiler` | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version). + `copyright` | The copyright line for the library as string. + `name` | The name of the library as string. + `platform` | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`. + `url` | The URL of the project as string. + `version` | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string). + + @liveexample{The following code shows an example output of the `meta()` + function.,meta} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @complexity Constant. + + @since 2.1.0 + */ +static basic_json meta() +{ +basic_json result; + +result["copyright"] = "(C) 2013-2017 Niels Lohmann"; +result["name"] = "JSON for Modern C++"; +result["url"] = "https://github.com/nlohmann/json"; +result["version"]["string"] = +std::to_string(NLOHMANN_JSON_VERSION_MAJOR) + "." + +std::to_string(NLOHMANN_JSON_VERSION_MINOR) + "." + +std::to_string(NLOHMANN_JSON_VERSION_PATCH); +result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR; +result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR; +result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH; + +#ifdef _WIN32 +result["platform"] = "win32"; +#elif defined __linux__ +result["platform"] = "linux"; +#elif defined __APPLE__ +result["platform"] = "apple"; +#elif defined __unix__ +result["platform"] = "unix"; +#else +result["platform"] = "unknown"; +#endif + +#if defined(__ICC) || defined(__INTEL_COMPILER) +result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; +#elif defined(__clang__) +result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; +#elif defined(__GNUC__) || defined(__GNUG__) +result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}}; +#elif defined(__HP_cc) || defined(__HP_aCC) +result["compiler"] = "hp" +#elif defined(__IBMCPP__) +result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; +#elif defined(_MSC_VER) +result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; +#elif defined(__PGI) +result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; +#elif defined(__SUNPRO_CC) +result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; +#else +result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; +#endif + +#ifdef __cplusplus +result["compiler"]["c++"] = std::to_string(__cplusplus); +#else +result["compiler"]["c++"] = "unknown"; +#endif +return result; +} + + +/////////////////////////// +// JSON value data types // +/////////////////////////// + +/// @name JSON value data types +/// The data types to store a JSON value. These types are derived from +/// the template arguments passed to class @ref basic_json. +/// @{ + +#if defined(JSON_HAS_CPP_14) +// Use transparent comparator if possible, combined with perfect forwarding +// on find() and count() calls prevents unnecessary string construction. +using object_comparator_t = std::less<>; +#else +using object_comparator_t = std::less; +#endif + +/*! + @brief a type for an object + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: + > An object is an unordered collection of zero or more name/value pairs, + > where a name is a string and a value is a string, number, boolean, null, + > object, or array. + + To store objects in C++, a type is defined by the template parameters + described below. + + @tparam ObjectType the container to store objects (e.g., `std::map` or + `std::unordered_map`) + @tparam StringType the type of the keys or names (e.g., `std::string`). + The comparison function `std::less` is used to order elements + inside the container. + @tparam AllocatorType the allocator to use for objects (e.g., + `std::allocator`) + + #### Default type + + With the default values for @a ObjectType (`std::map`), @a StringType + (`std::string`), and @a AllocatorType (`std::allocator`), the default + value for @a object_t is: + + @code {.cpp} + std::map< + std::string, // key_type + basic_json, // value_type + std::less, // key_compare + std::allocator> // allocator_type + > + @endcode + + #### Behavior + + The choice of @a object_t influences the behavior of the JSON class. With + the default type, objects have the following behavior: + + - When all names are unique, objects will be interoperable in the sense + that all software implementations receiving that object will agree on + the name-value mappings. + - When the names within an object are not unique, later stored name/value + pairs overwrite previously stored name/value pairs, leaving the used + names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will + be treated as equal and both stored as `{"key": 1}`. + - Internally, name/value pairs are stored in lexicographical order of the + names. Objects will also be serialized (see @ref dump) in this order. + For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored + and serialized as `{"a": 2, "b": 1}`. + - When comparing objects, the order of the name/value pairs is irrelevant. + This makes objects interoperable in the sense that they will not be + affected by these differences. For instance, `{"b": 1, "a": 2}` and + `{"a": 2, "b": 1}` will be treated as equal. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the object's limit of nesting is not explicitly constrained. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON object. + + #### Storage + + Objects are stored as pointers in a @ref basic_json type. That is, for any + access to object values, a pointer of type `object_t*` must be + dereferenced. + + @sa @ref array_t -- type for an array value + + @since version 1.0.0 + + @note The order name/value pairs are added to the object is *not* + preserved by the library. Therefore, iterating an object may return + name/value pairs in a different order than they were originally stored. In + fact, keys will be traversed in alphabetical order as `std::map` with + `std::less` is used by default. Please note this behavior conforms to [RFC + 7159](http://rfc7159.net/rfc7159), because any order implements the + specified "unordered" nature of JSON objects. + */ +using object_t = ObjectType>>; + +/*! + @brief a type for an array + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: + > An array is an ordered sequence of zero or more values. + + To store objects in C++, a type is defined by the template parameters + explained below. + + @tparam ArrayType container type to store arrays (e.g., `std::vector` or + `std::list`) + @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) + + #### Default type + + With the default values for @a ArrayType (`std::vector`) and @a + AllocatorType (`std::allocator`), the default value for @a array_t is: + + @code {.cpp} + std::vector< + basic_json, // value_type + std::allocator // allocator_type + > + @endcode + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the array's limit of nesting is not explicitly constrained. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON array. + + #### Storage + + Arrays are stored as pointers in a @ref basic_json type. That is, for any + access to array values, a pointer of type `array_t*` must be dereferenced. + + @sa @ref object_t -- type for an object value + + @since version 1.0.0 + */ +using array_t = ArrayType>; + +/*! + @brief a type for a string + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: + > A string is a sequence of zero or more Unicode characters. + + To store objects in C++, a type is defined by the template parameter + described below. Unicode values are split by the JSON class into + byte-sized characters during deserialization. + + @tparam StringType the container to store strings (e.g., `std::string`). + Note this container is used for keys/names in objects, see @ref object_t. + + #### Default type + + With the default values for @a StringType (`std::string`), the default + value for @a string_t is: + + @code {.cpp} + std::string + @endcode + + #### Encoding + + Strings are stored in UTF-8 encoding. Therefore, functions like + `std::string::size()` or `std::string::length()` return the number of + bytes in the string rather than the number of characters or glyphs. + + #### String comparison + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > Software implementations are typically required to test names of object + > members for equality. Implementations that transform the textual + > representation into sequences of Unicode code units and then perform the + > comparison numerically, code unit by code unit, are interoperable in the + > sense that implementations will agree in all cases on equality or + > inequality of two strings. For example, implementations that compare + > strings with escaped characters unconverted may incorrectly find that + > `"a\\b"` and `"a\u005Cb"` are not equal. + + This implementation is interoperable as it does compare strings code unit + by code unit. + + #### Storage + + String values are stored as pointers in a @ref basic_json type. That is, + for any access to string values, a pointer of type `string_t*` must be + dereferenced. + + @since version 1.0.0 + */ +using string_t = StringType; + +/*! + @brief a type for a boolean + + [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a + type which differentiates the two literals `true` and `false`. + + To store objects in C++, a type is defined by the template parameter @a + BooleanType which chooses the type to use. + + #### Default type + + With the default values for @a BooleanType (`bool`), the default value for + @a boolean_t is: + + @code {.cpp} + bool + @endcode + + #### Storage + + Boolean values are stored directly inside a @ref basic_json type. + + @since version 1.0.0 + */ +using boolean_t = BooleanType; + +/*! + @brief a type for a number (integer) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store integer numbers in C++, a type is defined by the template + parameter @a NumberIntegerType which chooses the type to use. + + #### Default type + + With the default values for @a NumberIntegerType (`int64_t`), the default + value for @a number_integer_t is: + + @code {.cpp} + int64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `9223372036854775807` (INT64_MAX) and the minimal integer number + that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers + that are out of range will yield over/underflow when used in a + constructor. During deserialization, too large or small integer numbers + will be automatically be stored as @ref number_unsigned_t or @ref + number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange of the exactly supported range [INT64_MIN, + INT64_MAX], this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ +using number_integer_t = NumberIntegerType; + +/*! + @brief a type for a number (unsigned) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store unsigned integer numbers in C++, a type is defined by the + template parameter @a NumberUnsignedType which chooses the type to use. + + #### Default type + + With the default values for @a NumberUnsignedType (`uint64_t`), the + default value for @a number_unsigned_t is: + + @code {.cpp} + uint64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `18446744073709551615` (UINT64_MAX) and the minimal integer + number that can be stored is `0`. Integer numbers that are out of range + will yield over/underflow when used in a constructor. During + deserialization, too large or small integer numbers will be automatically + be stored as @ref number_integer_t or @ref number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange (when considered in conjunction with the + number_integer_t type) of the exactly supported range [0, UINT64_MAX], + this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + @sa @ref number_integer_t -- type for number values (integer) + + @since version 2.0.0 + */ +using number_unsigned_t = NumberUnsignedType; + +/*! + @brief a type for a number (floating-point) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store floating-point numbers in C++, a type is defined by the template + parameter @a NumberFloatType which chooses the type to use. + + #### Default type + + With the default values for @a NumberFloatType (`double`), the default + value for @a number_float_t is: + + @code {.cpp} + double + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in floating-point literals will be ignored. Internally, + the value will be stored as decimal number. For instance, the C++ + floating-point literal `01.2` will be serialized to `1.2`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > This specification allows implementations to set limits on the range and + > precision of numbers accepted. Since software that implements IEEE + > 754-2008 binary64 (double precision) numbers is generally available and + > widely used, good interoperability can be achieved by implementations + > that expect no more precision or range than these provide, in the sense + > that implementations will approximate JSON numbers within the expected + > precision. + + This implementation does exactly follow this approach, as it uses double + precision floating-point numbers. Note values smaller than + `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` + will be stored as NaN internally and be serialized to `null`. + + #### Storage + + Floating-point number values are stored directly inside a @ref basic_json + type. + + @sa @ref number_integer_t -- type for number values (integer) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ +using number_float_t = NumberFloatType; + +/// @} + +private: + +/// helper for exception-safe object creation +template +static T* create(Args&& ... args) +{ +AllocatorType alloc; +using AllocatorTraits = std::allocator_traits>; + +auto deleter = [&](T * object) +{ +AllocatorTraits::deallocate(alloc, object, 1); +}; +std::unique_ptr object(AllocatorTraits::allocate(alloc, 1), deleter); +AllocatorTraits::construct(alloc, object.get(), std::forward(args)...); +assert(object != nullptr); +return object.release(); +} + +//////////////////////// +// JSON value storage // +//////////////////////// + +/*! + @brief a JSON value + + The actual storage for a JSON value of the @ref basic_json class. This + union combines the different storage types for the JSON value types + defined in @ref value_t. + + JSON type | value_t type | used type + --------- | --------------- | ------------------------ + object | object | pointer to @ref object_t + array | array | pointer to @ref array_t + string | string | pointer to @ref string_t + boolean | boolean | @ref boolean_t + number | number_integer | @ref number_integer_t + number | number_unsigned | @ref number_unsigned_t + number | number_float | @ref number_float_t + null | null | *no value is stored* + + @note Variable-length types (objects, arrays, and strings) are stored as + pointers. The size of the union should not exceed 64 bits if the default + value types are used. + + @since version 1.0.0 + */ +union json_value +{ +/// object (stored with pointer to save storage) +object_t* object; +/// array (stored with pointer to save storage) +array_t* array; +/// string (stored with pointer to save storage) +string_t* string; +/// boolean +boolean_t boolean; +/// number (integer) +number_integer_t number_integer; +/// number (unsigned integer) +number_unsigned_t number_unsigned; +/// number (floating-point) +number_float_t number_float; + +/// default constructor (for null values) +json_value() = default; +/// constructor for booleans +json_value(boolean_t v) noexcept : boolean(v) {} +/// constructor for numbers (integer) +json_value(number_integer_t v) noexcept : number_integer(v) {} +/// constructor for numbers (unsigned) +json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} +/// constructor for numbers (floating-point) +json_value(number_float_t v) noexcept : number_float(v) {} +/// constructor for empty values of a given type +json_value(value_t t) +{ +switch (t) +{ +case value_t::object: +{ +object = create(); +break; +} + +case value_t::array: +{ +array = create(); +break; +} + +case value_t::string: +{ +string = create(""); +break; +} + +case value_t::boolean: +{ +boolean = boolean_t(false); +break; +} + +case value_t::number_integer: +{ +number_integer = number_integer_t(0); +break; +} + +case value_t::number_unsigned: +{ +number_unsigned = number_unsigned_t(0); +break; +} + +case value_t::number_float: +{ +number_float = number_float_t(0.0); +break; +} + +case value_t::null: +{ +object = nullptr; // silence warning, see #821 +break; +} + +default: +{ +object = nullptr; // silence warning, see #821 +if (JSON_UNLIKELY(t == value_t::null)) +{ +JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.1.0")); // LCOV_EXCL_LINE +} +break; +} +} +} + +/// constructor for strings +json_value(const string_t& value) +{ +string = create(value); +} + +/// constructor for rvalue strings +json_value(string_t&& value) +{ +string = create(std::move(value)); +} + +/// constructor for objects +json_value(const object_t& value) +{ +object = create(value); +} + +/// constructor for rvalue objects +json_value(object_t&& value) +{ +object = create(std::move(value)); +} + +/// constructor for arrays +json_value(const array_t& value) +{ +array = create(value); +} + +/// constructor for rvalue arrays +json_value(array_t&& value) +{ +array = create(std::move(value)); +} + +void destroy(value_t t) noexcept +{ +switch (t) +{ +case value_t::object: +{ +AllocatorType alloc; +std::allocator_traits::destroy(alloc, object); +std::allocator_traits::deallocate(alloc, object, 1); +break; +} + +case value_t::array: +{ +AllocatorType alloc; +std::allocator_traits::destroy(alloc, array); +std::allocator_traits::deallocate(alloc, array, 1); +break; +} + +case value_t::string: +{ +AllocatorType alloc; +std::allocator_traits::destroy(alloc, string); +std::allocator_traits::deallocate(alloc, string, 1); +break; +} + +default: +{ +break; +} +} +} +}; + +/*! + @brief checks the class invariants + + This function asserts the class invariants. It needs to be called at the + end of every constructor to make sure that created objects respect the + invariant. Furthermore, it has to be called each time the type of a JSON + value is changed, because the invariant expresses a relationship between + @a m_type and @a m_value. + */ +void assert_invariant() const noexcept +{ +assert(m_type != value_t::object or m_value.object != nullptr); +assert(m_type != value_t::array or m_value.array != nullptr); +assert(m_type != value_t::string or m_value.string != nullptr); +} + +public: +////////////////////////// +// JSON parser callback // +////////////////////////// + +/*! + @brief parser event types + + The parser callback distinguishes the following events: + - `object_start`: the parser read `{` and started to process a JSON object + - `key`: the parser read a key of a value in an object + - `object_end`: the parser read `}` and finished processing a JSON object + - `array_start`: the parser read `[` and started to process a JSON array + - `array_end`: the parser read `]` and finished processing a JSON array + - `value`: the parser finished reading a JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + @sa @ref parser_callback_t for more information and examples + */ +using parse_event_t = typename parser::parse_event_t; + +/*! + @brief per-element parser callback type + + With a parser callback function, the result of parsing a JSON text can be + influenced. When passed to @ref parse, it is called on certain events + (passed as @ref parse_event_t via parameter @a event) with a set recursion + depth @a depth and context JSON value @a parsed. The return value of the + callback function is a boolean indicating whether the element that emitted + the callback shall be kept or not. + + We distinguish six scenarios (determined by the event type) in which the + callback function can be called. The following table describes the values + of the parameters @a depth, @a event, and @a parsed. + + parameter @a event | description | parameter @a depth | parameter @a parsed + ------------------ | ----------- | ------------------ | ------------------- + parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded + parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key + parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object + parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded + parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array + parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + Discarding a value (i.e., returning `false`) has different effects + depending on the context in which function was called: + + - Discarded values in structured types are skipped. That is, the parser + will behave as if the discarded value was never read. + - In case a value outside a structured type is skipped, it is replaced + with `null`. This case happens if the top-level element is skipped. + + @param[in] depth the depth of the recursion during parsing + + @param[in] event an event of type parse_event_t indicating the context in + the callback function has been called + + @param[in,out] parsed the current intermediate parse result; note that + writing to this value has no effect for parse_event_t::key events + + @return Whether the JSON value which called the function during parsing + should be kept (`true`) or not (`false`). In the latter case, it is either + skipped completely or replaced by an empty discarded object. + + @sa @ref parse for examples + + @since version 1.0.0 + */ +using parser_callback_t = typename parser::parser_callback_t; + + +////////////////// +// constructors // +////////////////// + +/// @name constructors and destructors +/// Constructors of class @ref basic_json, copy/move constructor, copy +/// assignment, static functions creating objects, and the destructor. +/// @{ + +/*! + @brief create an empty value with a given type + + Create an empty JSON value with a given type. The value will be default + initialized with an empty value which depends on the type: + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @param[in] v the type of the value to create + + @complexity Constant. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows the constructor for different @ref + value_t values,basic_json__value_t} + + @sa @ref clear() -- restores the postcondition of this constructor + + @since version 1.0.0 + */ +basic_json(const value_t v) +: m_type(v), m_value(v) +{ +assert_invariant(); +} + +/*! + @brief create a null object + + Create a `null` JSON value. It either takes a null pointer as parameter + (explicitly creating `null`) or no parameter (implicitly creating `null`). + The passed null pointer itself is not read -- it is only used to choose + the right constructor. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @liveexample{The following code shows the constructor with and without a + null pointer parameter.,basic_json__nullptr_t} + + @since version 1.0.0 + */ +basic_json(std::nullptr_t = nullptr) noexcept +: basic_json(value_t::null) +{ +assert_invariant(); +} + +/*! + @brief create a JSON value + + This is a "catch all" constructor for all compatible JSON types; that is, + types for which a `to_json()` method exists. The constructor forwards the + parameter @a val to that method (to `json_serializer::to_json` method + with `U = uncvref_t`, to be exact). + + Template type @a CompatibleType includes, but is not limited to, the + following types: + - **arrays**: @ref array_t and all kinds of compatible containers such as + `std::vector`, `std::deque`, `std::list`, `std::forward_list`, + `std::array`, `std::valarray`, `std::set`, `std::unordered_set`, + `std::multiset`, and `std::unordered_multiset` with a `value_type` from + which a @ref basic_json value can be constructed. + - **objects**: @ref object_t and all kinds of compatible associative + containers such as `std::map`, `std::unordered_map`, `std::multimap`, + and `std::unordered_multimap` with a `key_type` compatible to + @ref string_t and a `value_type` from which a @ref basic_json value can + be constructed. + - **strings**: @ref string_t, string literals, and all compatible string + containers can be used. + - **numbers**: @ref number_integer_t, @ref number_unsigned_t, + @ref number_float_t, and all convertible number types such as `int`, + `size_t`, `int64_t`, `float` or `double` can be used. + - **boolean**: @ref boolean_t / `bool` can be used. + + See the examples below. + + @tparam CompatibleType a type such that: + - @a CompatibleType is not derived from `std::istream`, + - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move + constructors), + - @a CompatibleType is not a @ref basic_json nested type (e.g., + @ref json_pointer, @ref iterator, etc ...) + - @ref @ref json_serializer has a + `to_json(basic_json_t&, CompatibleType&&)` method + + @tparam U = `uncvref_t` + + @param[in] val the value to be forwarded to the respective constructor + + @complexity Usually linear in the size of the passed @a val, also + depending on the implementation of the called `to_json()` + method. + + @exceptionsafety Depends on the called constructor. For types directly + supported by the library (i.e., all types for which no `to_json()` function + was provided), strong guarantee holds: if an exception is thrown, there are + no changes to any JSON value. + + @liveexample{The following code shows the constructor with several + compatible types.,basic_json__CompatibleType} + + @since version 2.1.0 + */ +template , +detail::enable_if_t< +detail::is_compatible_type::value, int> = 0> +basic_json(CompatibleType && val) noexcept(noexcept( +JSONSerializer::to_json(std::declval(), +std::forward(val)))) +{ +JSONSerializer::to_json(*this, std::forward(val)); +assert_invariant(); +} + +/*! + @brief create a container (array or object) from an initializer list + + Creates a JSON value of type array or object from the passed initializer + list @a init. In case @a type_deduction is `true` (default), the type of + the JSON value to be created is deducted from the initializer list @a init + according to the following rules: + + 1. If the list is empty, an empty JSON object value `{}` is created. + 2. If the list consists of pairs whose first element is a string, a JSON + object value is created where the first elements of the pairs are + treated as keys and the second elements are as values. + 3. In all other cases, an array is created. + + The rules aim to create the best fit between a C++ initializer list and + JSON values. The rationale is as follows: + + 1. The empty initializer list is written as `{}` which is exactly an empty + JSON object. + 2. C++ has no way of describing mapped types other than to list a list of + pairs. As JSON requires that keys must be of type string, rule 2 is the + weakest constraint one can pose on initializer lists to interpret them + as an object. + 3. In all other cases, the initializer list could not be interpreted as + JSON object type, so interpreting it as JSON array type is safe. + + With the rules described above, the following JSON values cannot be + expressed by an initializer list: + + - the empty array (`[]`): use @ref array(initializer_list_t) + with an empty initializer list in this case + - arrays whose elements satisfy rule 2: use @ref + array(initializer_list_t) with the same initializer list + in this case + + @note When used without parentheses around an empty initializer list, @ref + basic_json() is called instead of this function, yielding the JSON null + value. + + @param[in] init initializer list with JSON values + + @param[in] type_deduction internal parameter; when set to `true`, the type + of the JSON value is deducted from the initializer list @a init; when set + to `false`, the type provided via @a manual_type is forced. This mode is + used by the functions @ref array(initializer_list_t) and + @ref object(initializer_list_t). + + @param[in] manual_type internal parameter; when @a type_deduction is set + to `false`, the created JSON value will use the provided type (only @ref + value_t::array and @ref value_t::object are valid); when @a type_deduction + is set to `true`, this parameter has no effect + + @throw type_error.301 if @a type_deduction is `false`, @a manual_type is + `value_t::object`, but @a init contains an element which is not a pair + whose first element is a string. In this case, the constructor could not + create an object. If @a type_deduction would have be `true`, an array + would have been created. See @ref object(initializer_list_t) + for an example. + + @complexity Linear in the size of the initializer list @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The example below shows how JSON values are created from + initializer lists.,basic_json__list_init_t} + + @sa @ref array(initializer_list_t) -- create a JSON array + value from an initializer list + @sa @ref object(initializer_list_t) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ +basic_json(initializer_list_t init, +bool type_deduction = true, +value_t manual_type = value_t::array) +{ +// check if each element is an array with two elements whose first +// element is a string +bool is_an_object = std::all_of(init.begin(), init.end(), +[](const detail::json_ref& element_ref) +{ +return (element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string()); +}); + +// adjust type if type deduction is not wanted +if (not type_deduction) +{ +// if array is wanted, do not create an object though possible +if (manual_type == value_t::array) +{ +is_an_object = false; +} + +// if object is wanted but impossible, throw an exception +if (JSON_UNLIKELY(manual_type == value_t::object and not is_an_object)) +{ +JSON_THROW(type_error::create(301, "cannot create object from initializer list")); +} +} + +if (is_an_object) +{ +// the initializer list is a list of pairs -> create object +m_type = value_t::object; +m_value = value_t::object; + +std::for_each(init.begin(), init.end(), [this](const detail::json_ref& element_ref) +{ +auto element = element_ref.moved_or_copied(); +m_value.object->emplace( +std::move(*((*element.m_value.array)[0].m_value.string)), +std::move((*element.m_value.array)[1])); +}); +} +else +{ +// the initializer list describes an array -> create array +m_type = value_t::array; +m_value.array = create(init.begin(), init.end()); +} + +assert_invariant(); +} + +/*! + @brief explicitly create an array from an initializer list + + Creates a JSON array value from a given initializer list. That is, given a + list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the + initializer list is empty, the empty array `[]` is created. + + @note This function is only needed to express two edge cases that cannot + be realized with the initializer list constructor (@ref + basic_json(initializer_list_t, bool, value_t)). These cases + are: + 1. creating an array whose elements are all pairs whose first element is a + string -- in this case, the initializer list constructor would create an + object, taking the first elements as keys + 2. creating an empty array -- passing the empty initializer list to the + initializer list constructor yields an empty object + + @param[in] init initializer list with JSON values to create an array from + (optional) + + @return JSON array value + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows an example for the `array` + function.,array} + + @sa @ref basic_json(initializer_list_t, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref object(initializer_list_t) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ +static basic_json array(initializer_list_t init = {}) +{ +return basic_json(init, false, value_t::array); +} + +/*! + @brief explicitly create an object from an initializer list + + Creates a JSON object value from a given initializer list. The initializer + lists elements must be pairs, and their first elements must be strings. If + the initializer list is empty, the empty object `{}` is created. + + @note This function is only added for symmetry reasons. In contrast to the + related function @ref array(initializer_list_t), there are + no cases which can only be expressed by this function. That is, any + initializer list @a init can also be passed to the initializer list + constructor @ref basic_json(initializer_list_t, bool, value_t). + + @param[in] init initializer list to create an object from (optional) + + @return JSON object value + + @throw type_error.301 if @a init is not a list of pairs whose first + elements are strings. In this case, no object can be created. When such a + value is passed to @ref basic_json(initializer_list_t, bool, value_t), + an array would have been created from the passed initializer list @a init. + See example below. + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows an example for the `object` + function.,object} + + @sa @ref basic_json(initializer_list_t, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref array(initializer_list_t) -- create a JSON array + value from an initializer list + + @since version 1.0.0 + */ +static basic_json object(initializer_list_t init = {}) +{ +return basic_json(init, false, value_t::object); +} + +/*! + @brief construct an array with count copies of given value + + Constructs a JSON array value by creating @a cnt copies of a passed value. + In case @a cnt is `0`, an empty array is created. + + @param[in] cnt the number of JSON copies of @a val to create + @param[in] val the JSON value to copy + + @post `std::distance(begin(),end()) == cnt` holds. + + @complexity Linear in @a cnt. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows examples for the @ref + basic_json(size_type\, const basic_json&) + constructor.,basic_json__size_type_basic_json} + + @since version 1.0.0 + */ +basic_json(size_type cnt, const basic_json& val) +: m_type(value_t::array) +{ +m_value.array = create(cnt, val); +assert_invariant(); +} + +/*! + @brief construct a JSON container given an iterator range + + Constructs the JSON value with the contents of the range `[first, last)`. + The semantics depends on the different types a JSON value can have: + - In case of a null type, invalid_iterator.206 is thrown. + - In case of other primitive types (number, boolean, or string), @a first + must be `begin()` and @a last must be `end()`. In this case, the value is + copied. Otherwise, invalid_iterator.204 is thrown. + - In case of structured types (array, object), the constructor behaves as + similar versions for `std::vector` or `std::map`; that is, a JSON array + or object is constructed from the values in the range. + + @tparam InputIT an input iterator type (@ref iterator or @ref + const_iterator) + + @param[in] first begin of the range to copy from (included) + @param[in] last end of the range to copy from (excluded) + + @pre Iterators @a first and @a last must be initialized. **This + precondition is enforced with an assertion (see warning).** If + assertions are switched off, a violation of this precondition yields + undefined behavior. + + @pre Range `[first, last)` is valid. Usually, this precondition cannot be + checked efficiently. Only certain edge cases are detected; see the + description of the exceptions below. A violation of this precondition + yields undefined behavior. + + @warning A precondition is enforced with a runtime assertion that will + result in calling `std::abort` if this precondition is not met. + Assertions can be disabled by defining `NDEBUG` at compile time. + See http://en.cppreference.com/w/cpp/error/assert for more + information. + + @throw invalid_iterator.201 if iterators @a first and @a last are not + compatible (i.e., do not belong to the same JSON value). In this case, + the range `[first, last)` is undefined. + @throw invalid_iterator.204 if iterators @a first and @a last belong to a + primitive type (number, boolean, or string), but @a first does not point + to the first element any more. In this case, the range `[first, last)` is + undefined. See example code below. + @throw invalid_iterator.206 if iterators @a first and @a last belong to a + null value. In this case, the range `[first, last)` is undefined. + + @complexity Linear in distance between @a first and @a last. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The example below shows several ways to create JSON values by + specifying a subrange with iterators.,basic_json__InputIt_InputIt} + + @since version 1.0.0 + */ +template::value or +std::is_same::value, int>::type = 0> +basic_json(InputIT first, InputIT last) +{ +assert(first.m_object != nullptr); +assert(last.m_object != nullptr); + +// make sure iterator fits the current value +if (JSON_UNLIKELY(first.m_object != last.m_object)) +{ +JSON_THROW(invalid_iterator::create(201, "iterators are not compatible")); +} + +// copy type from first iterator +m_type = first.m_object->m_type; + +// check if iterator range is complete for primitive values +switch (m_type) +{ +case value_t::boolean: +case value_t::number_float: +case value_t::number_integer: +case value_t::number_unsigned: +case value_t::string: +{ +if (JSON_UNLIKELY(not first.m_it.primitive_iterator.is_begin() +or not last.m_it.primitive_iterator.is_end())) +{ +JSON_THROW(invalid_iterator::create(204, "iterators out of range")); +} +break; +} + +default: +break; +} + +switch (m_type) +{ +case value_t::number_integer: +{ +m_value.number_integer = first.m_object->m_value.number_integer; +break; +} + +case value_t::number_unsigned: +{ +m_value.number_unsigned = first.m_object->m_value.number_unsigned; +break; +} + +case value_t::number_float: +{ +m_value.number_float = first.m_object->m_value.number_float; +break; +} + +case value_t::boolean: +{ +m_value.boolean = first.m_object->m_value.boolean; +break; +} + +case value_t::string: +{ +m_value = *first.m_object->m_value.string; +break; +} + +case value_t::object: +{ +m_value.object = create(first.m_it.object_iterator, +last.m_it.object_iterator); +break; +} + +case value_t::array: +{ +m_value.array = create(first.m_it.array_iterator, +last.m_it.array_iterator); +break; +} + +default: +JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " + +std::string(first.m_object->type_name()))); +} + +assert_invariant(); +} + + +/////////////////////////////////////// +// other constructors and destructor // +/////////////////////////////////////// + +/// @private +basic_json(const detail::json_ref& ref) +: basic_json(ref.moved_or_copied()) +{} + +/*! + @brief copy constructor + + Creates a copy of a given JSON value. + + @param[in] other the JSON value to copy + + @post `*this == other` + + @complexity Linear in the size of @a other. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - As postcondition, it holds: `other == basic_json(other)`. + + @liveexample{The following code shows an example for the copy + constructor.,basic_json__basic_json} + + @since version 1.0.0 + */ +basic_json(const basic_json& other) +: m_type(other.m_type) +{ +// check of passed value is valid +other.assert_invariant(); + +switch (m_type) +{ +case value_t::object: +{ +m_value = *other.m_value.object; +break; +} + +case value_t::array: +{ +m_value = *other.m_value.array; +break; +} + +case value_t::string: +{ +m_value = *other.m_value.string; +break; +} + +case value_t::boolean: +{ +m_value = other.m_value.boolean; +break; +} + +case value_t::number_integer: +{ +m_value = other.m_value.number_integer; +break; +} + +case value_t::number_unsigned: +{ +m_value = other.m_value.number_unsigned; +break; +} + +case value_t::number_float: +{ +m_value = other.m_value.number_float; +break; +} + +default: +break; +} + +assert_invariant(); +} + +/*! + @brief move constructor + + Move constructor. Constructs a JSON value with the contents of the given + value @a other using move semantics. It "steals" the resources from @a + other and leaves it as JSON null value. + + @param[in,out] other value to move to this object + + @post `*this` has the same value as @a other before the call. + @post @a other is a JSON null value. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @requirement This function helps `basic_json` satisfying the + [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible) + requirements. + + @liveexample{The code below shows the move constructor explicitly called + via std::move.,basic_json__moveconstructor} + + @since version 1.0.0 + */ +basic_json(basic_json&& other) noexcept +: m_type(std::move(other.m_type)), +m_value(std::move(other.m_value)) +{ +// check that passed value is valid +other.assert_invariant(); + +// invalidate payload +other.m_type = value_t::null; +other.m_value = {}; + +assert_invariant(); +} + +/*! + @brief copy assignment + + Copy assignment operator. Copies a JSON value via the "copy and swap" + strategy: It is expressed in terms of the copy constructor, destructor, + and the `swap()` member function. + + @param[in] other value to copy from + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + + @liveexample{The code below shows and example for the copy assignment. It + creates a copy of value `a` which is then swapped with `b`. Finally\, the + copy of `a` (which is the null value after the swap) is + destroyed.,basic_json__copyassignment} + + @since version 1.0.0 + */ +reference& operator=(basic_json other) noexcept ( +std::is_nothrow_move_constructible::value and +std::is_nothrow_move_assignable::value and +std::is_nothrow_move_constructible::value and +std::is_nothrow_move_assignable::value +) +{ +// check that passed value is valid +other.assert_invariant(); + +using std::swap; +swap(m_type, other.m_type); +swap(m_value, other.m_value); + +assert_invariant(); +return *this; +} + +/*! + @brief destructor + + Destroys the JSON value and frees all allocated memory. + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - All stored elements are destroyed and all memory is freed. + + @since version 1.0.0 + */ +~basic_json() noexcept +{ +assert_invariant(); +m_value.destroy(m_type); +} + +/// @} + +public: +/////////////////////// +// object inspection // +/////////////////////// + +/// @name object inspection +/// Functions to inspect the type of a JSON value. +/// @{ + +/*! + @brief serialization + + Serialization function for JSON values. The function tries to mimic + Python's `json.dumps()` function, and currently supports its @a indent + and @a ensure_ascii parameters. + + @param[in] indent If indent is nonnegative, then array elements and object + members will be pretty-printed with that indent level. An indent level of + `0` will only insert newlines. `-1` (the default) selects the most compact + representation. + @param[in] indent_char The character to use for indentation if @a indent is + greater than `0`. The default is ` ` (space). + @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters + in the output are escaped with `\uXXXX` sequences, and the result consists + of ASCII characters only. + + @return string containing the serialization of the JSON value + + @throw type_error.316 if a string stored inside the JSON value is not + UTF-8 encoded + + @complexity Linear. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @liveexample{The following example shows the effect of different @a indent\, + @a indent_char\, and @a ensure_ascii parameters to the result of the + serialization.,dump} + + @see https://docs.python.org/2/library/json.html#json.dump + + @since version 1.0.0; indentation character @a indent_char, option + @a ensure_ascii and exceptions added in version 3.0.0 + */ +string_t dump(const int indent = -1, const char indent_char = ' ', +const bool ensure_ascii = false) const +{ +string_t result; +serializer s(detail::output_adapter(result), indent_char); + +if (indent >= 0) +{ +s.dump(*this, true, ensure_ascii, static_cast(indent)); +} +else +{ +s.dump(*this, false, ensure_ascii, 0); +} + +return result; +} + +/*! + @brief return the type of the JSON value (explicit) + + Return the type of the JSON value as a value from the @ref value_t + enumeration. + + @return the type of the JSON value + Value type | return value + ------------------------- | ------------------------- + null | value_t::null + boolean | value_t::boolean + string | value_t::string + number (integer) | value_t::number_integer + number (unsigned integer) | value_t::number_unsigned + number (floating-point) | value_t::number_float + object | value_t::object + array | value_t::array + discarded | value_t::discarded + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `type()` for all JSON + types.,type} + + @sa @ref operator value_t() -- return the type of the JSON value (implicit) + @sa @ref type_name() -- return the type as string + + @since version 1.0.0 + */ +constexpr value_t type() const noexcept +{ +return m_type; +} + +/*! + @brief return whether type is primitive + + This function returns true if and only if the JSON type is primitive + (string, number, boolean, or null). + + @return `true` if type is primitive (string, number, boolean, or null), + `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_primitive()` for all JSON + types.,is_primitive} + + @sa @ref is_structured() -- returns whether JSON value is structured + @sa @ref is_null() -- returns whether JSON value is `null` + @sa @ref is_string() -- returns whether JSON value is a string + @sa @ref is_boolean() -- returns whether JSON value is a boolean + @sa @ref is_number() -- returns whether JSON value is a number + + @since version 1.0.0 + */ +constexpr bool is_primitive() const noexcept +{ +return is_null() or is_string() or is_boolean() or is_number(); +} + +/*! + @brief return whether type is structured + + This function returns true if and only if the JSON type is structured + (array or object). + + @return `true` if type is structured (array or object), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_structured()` for all JSON + types.,is_structured} + + @sa @ref is_primitive() -- returns whether value is primitive + @sa @ref is_array() -- returns whether value is an array + @sa @ref is_object() -- returns whether value is an object + + @since version 1.0.0 + */ +constexpr bool is_structured() const noexcept +{ +return is_array() or is_object(); +} + +/*! + @brief return whether value is null + + This function returns true if and only if the JSON value is null. + + @return `true` if type is null, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_null()` for all JSON + types.,is_null} + + @since version 1.0.0 + */ +constexpr bool is_null() const noexcept +{ +return (m_type == value_t::null); +} + +/*! + @brief return whether value is a boolean + + This function returns true if and only if the JSON value is a boolean. + + @return `true` if type is boolean, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_boolean()` for all JSON + types.,is_boolean} + + @since version 1.0.0 + */ +constexpr bool is_boolean() const noexcept +{ +return (m_type == value_t::boolean); +} + +/*! + @brief return whether value is a number + + This function returns true if and only if the JSON value is a number. This + includes both integer (signed and unsigned) and floating-point values. + + @return `true` if type is number (regardless whether integer, unsigned + integer or floating-type), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number()` for all JSON + types.,is_number} + + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ +constexpr bool is_number() const noexcept +{ +return is_number_integer() or is_number_float(); +} + +/*! + @brief return whether value is an integer number + + This function returns true if and only if the JSON value is a signed or + unsigned integer number. This excludes floating-point values. + + @return `true` if type is an integer or unsigned integer number, `false` + otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_integer()` for all + JSON types.,is_number_integer} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ +constexpr bool is_number_integer() const noexcept +{ +return (m_type == value_t::number_integer or m_type == value_t::number_unsigned); +} + +/*! + @brief return whether value is an unsigned integer number + + This function returns true if and only if the JSON value is an unsigned + integer number. This excludes floating-point and signed integer values. + + @return `true` if type is an unsigned integer number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_unsigned()` for all + JSON types.,is_number_unsigned} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 2.0.0 + */ +constexpr bool is_number_unsigned() const noexcept +{ +return (m_type == value_t::number_unsigned); +} + +/*! + @brief return whether value is a floating-point number + + This function returns true if and only if the JSON value is a + floating-point number. This excludes signed and unsigned integer values. + + @return `true` if type is a floating-point number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_float()` for all + JSON types.,is_number_float} + + @sa @ref is_number() -- check if value is number + @sa @ref is_number_integer() -- check if value is an integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + + @since version 1.0.0 + */ +constexpr bool is_number_float() const noexcept +{ +return (m_type == value_t::number_float); +} + +/*! + @brief return whether value is an object + + This function returns true if and only if the JSON value is an object. + + @return `true` if type is object, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_object()` for all JSON + types.,is_object} + + @since version 1.0.0 + */ +constexpr bool is_object() const noexcept +{ +return (m_type == value_t::object); +} + +/*! + @brief return whether value is an array + + This function returns true if and only if the JSON value is an array. + + @return `true` if type is array, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_array()` for all JSON + types.,is_array} + + @since version 1.0.0 + */ +constexpr bool is_array() const noexcept +{ +return (m_type == value_t::array); +} + +/*! + @brief return whether value is a string + + This function returns true if and only if the JSON value is a string. + + @return `true` if type is string, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_string()` for all JSON + types.,is_string} + + @since version 1.0.0 + */ +constexpr bool is_string() const noexcept +{ +return (m_type == value_t::string); +} + +/*! + @brief return whether value is discarded + + This function returns true if and only if the JSON value was discarded + during parsing with a callback function (see @ref parser_callback_t). + + @note This function will always be `false` for JSON values after parsing. + That is, discarded values can only occur during parsing, but will be + removed when inside a structured value or replaced by null in other cases. + + @return `true` if type is discarded, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_discarded()` for all JSON + types.,is_discarded} + + @since version 1.0.0 + */ +constexpr bool is_discarded() const noexcept +{ +return (m_type == value_t::discarded); +} + +/*! + @brief return the type of the JSON value (implicit) + + Implicitly return the type of the JSON value as a value from the @ref + value_t enumeration. + + @return the type of the JSON value + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies the @ref value_t operator for + all JSON types.,operator__value_t} + + @sa @ref type() -- return the type of the JSON value (explicit) + @sa @ref type_name() -- return the type as string + + @since version 1.0.0 + */ +constexpr operator value_t() const noexcept +{ +return m_type; +} + +/// @} + +private: +////////////////// +// value access // +////////////////// + +/// get a boolean (explicit) +boolean_t get_impl(boolean_t* /*unused*/) const +{ +if (JSON_LIKELY(is_boolean())) +{ +return m_value.boolean; +} + +JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(type_name()))); +} + +/// get a pointer to the value (object) +object_t* get_impl_ptr(object_t* /*unused*/) noexcept +{ +return is_object() ? m_value.object : nullptr; +} + +/// get a pointer to the value (object) +constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept +{ +return is_object() ? m_value.object : nullptr; +} + +/// get a pointer to the value (array) +array_t* get_impl_ptr(array_t* /*unused*/) noexcept +{ +return is_array() ? m_value.array : nullptr; +} + +/// get a pointer to the value (array) +constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept +{ +return is_array() ? m_value.array : nullptr; +} + +/// get a pointer to the value (string) +string_t* get_impl_ptr(string_t* /*unused*/) noexcept +{ +return is_string() ? m_value.string : nullptr; +} + +/// get a pointer to the value (string) +constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept +{ +return is_string() ? m_value.string : nullptr; +} + +/// get a pointer to the value (boolean) +boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept +{ +return is_boolean() ? &m_value.boolean : nullptr; +} + +/// get a pointer to the value (boolean) +constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept +{ +return is_boolean() ? &m_value.boolean : nullptr; +} + +/// get a pointer to the value (integer number) +number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept +{ +return is_number_integer() ? &m_value.number_integer : nullptr; +} + +/// get a pointer to the value (integer number) +constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept +{ +return is_number_integer() ? &m_value.number_integer : nullptr; +} + +/// get a pointer to the value (unsigned number) +number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept +{ +return is_number_unsigned() ? &m_value.number_unsigned : nullptr; +} + +/// get a pointer to the value (unsigned number) +constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept +{ +return is_number_unsigned() ? &m_value.number_unsigned : nullptr; +} + +/// get a pointer to the value (floating-point number) +number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept +{ +return is_number_float() ? &m_value.number_float : nullptr; +} + +/// get a pointer to the value (floating-point number) +constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept +{ +return is_number_float() ? &m_value.number_float : nullptr; +} + +/*! + @brief helper function to implement get_ref() + + This function helps to implement get_ref() without code duplication for + const and non-const overloads + + @tparam ThisType will be deduced as `basic_json` or `const basic_json` + + @throw type_error.303 if ReferenceType does not match underlying value + type of the current JSON + */ +template +static ReferenceType get_ref_impl(ThisType& obj) +{ +// delegate the call to get_ptr<>() +auto ptr = obj.template get_ptr::type>(); + +if (JSON_LIKELY(ptr != nullptr)) +{ +return *ptr; +} + +JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + std::string(obj.type_name()))); +} + +public: +/// @name value access +/// Direct access to the stored value of a JSON value. +/// @{ + +/*! + @brief get special-case overload + + This overloads avoids a lot of template boilerplate, it can be seen as the + identity method + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this + + @complexity Constant. + + @since version 2.1.0 + */ +template::type, basic_json_t>::value, +int> = 0> +basic_json get() const +{ +return *this; +} + +/*! + @brief get a value (explicit) + + Explicit type conversion between the JSON value and a compatible value + which is [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) + and [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json, + - @ref json_serializer has a `from_json()` method of the form + `void from_json(const basic_json&, ValueType&)`, and + - @ref json_serializer does not have a `from_json()` method of + the form `ValueType from_json(const basic_json&)` + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get__ValueType_const} + + @since version 2.1.0 + */ +template, +detail::enable_if_t < +not std::is_same::value and +detail::has_from_json::value and +not detail::has_non_default_from_json::value, +int> = 0> +ValueType get() const noexcept(noexcept( +JSONSerializer::from_json(std::declval(), std::declval()))) +{ +// we cannot static_assert on ValueTypeCV being non-const, because +// there is support for get(), which is why we +// still need the uncvref +static_assert(not std::is_reference::value, +"get() cannot be used with reference types, you might want to use get_ref()"); +static_assert(std::is_default_constructible::value, +"types must be DefaultConstructible when used with get()"); + +ValueType ret; +JSONSerializer::from_json(*this, ret); +return ret; +} + +/*! + @brief get a value (explicit); special case + + Explicit type conversion between the JSON value and a compatible value + which is **not** [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) + and **not** [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + return JSONSerializer::from_json(*this); + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json and + - @ref json_serializer has a `from_json()` method of the form + `ValueType from_json(const basic_json&)` + + @note If @ref json_serializer has both overloads of + `from_json()`, this one is chosen. + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @since version 2.1.0 + */ +template, +detail::enable_if_t::value and +detail::has_non_default_from_json::value, +int> = 0> +ValueType get() const noexcept(noexcept( +JSONSerializer::from_json(std::declval()))) +{ +static_assert(not std::is_reference::value, +"get() cannot be used with reference types, you might want to use get_ref()"); +return JSONSerializer::from_json(*this); +} + +/*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object + changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ +template::value, int>::type = 0> +PointerType get() noexcept +{ +// delegate the call to get_ptr +return get_ptr(); +} + +/*! + @brief get a pointer value (explicit) + @copydoc get() + */ +template::value, int>::type = 0> +constexpr const PointerType get() const noexcept +{ +// delegate the call to get_ptr +return get_ptr(); +} + +/*! + @brief get a pointer value (implicit) + + Implicit pointer access to the internally stored JSON value. No copies are + made. + + @warning Writing data to the pointee of the result yields an undefined + state. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. Enforced by a static + assertion. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get_ptr} + + @since version 1.0.0 + */ +template::value, int>::type = 0> +PointerType get_ptr() noexcept +{ +// get the type of the PointerType (remove pointer and const) +using pointee_t = typename std::remove_const::type>::type>::type; +// make sure the type matches the allowed types +static_assert( +std::is_same::value +or std::is_same::value +or std::is_same::value +or std::is_same::value +or std::is_same::value +or std::is_same::value +or std::is_same::value +, "incompatible pointer type"); + +// delegate the call to get_impl_ptr<>() +return get_impl_ptr(static_cast(nullptr)); +} + +/*! + @brief get a pointer value (implicit) + @copydoc get_ptr() + */ +template::value and +std::is_const::type>::value, int>::type = 0> +constexpr const PointerType get_ptr() const noexcept +{ +// get the type of the PointerType (remove pointer and const) +using pointee_t = typename std::remove_const::type>::type>::type; +// make sure the type matches the allowed types +static_assert( +std::is_same::value +or std::is_same::value +or std::is_same::value +or std::is_same::value +or std::is_same::value +or std::is_same::value +or std::is_same::value +, "incompatible pointer type"); + +// delegate the call to get_impl_ptr<>() const +return get_impl_ptr(static_cast(nullptr)); +} + +/*! + @brief get a reference value (implicit) + + Implicit reference access to the internally stored JSON value. No copies + are made. + + @warning Writing data to the referee of the result yields an undefined + state. + + @tparam ReferenceType reference type; must be a reference to @ref array_t, + @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or + @ref number_float_t. Enforced by static assertion. + + @return reference to the internally stored JSON value if the requested + reference type @a ReferenceType fits to the JSON value; throws + type_error.303 otherwise + + @throw type_error.303 in case passed type @a ReferenceType is incompatible + with the stored JSON value; see example below + + @complexity Constant. + + @liveexample{The example shows several calls to `get_ref()`.,get_ref} + + @since version 1.1.0 + */ +template::value, int>::type = 0> +ReferenceType get_ref() +{ +// delegate call to get_ref_impl +return get_ref_impl(*this); +} + +/*! + @brief get a reference value (implicit) + @copydoc get_ref() + */ +template::value and +std::is_const::type>::value, int>::type = 0> +ReferenceType get_ref() const +{ +// delegate call to get_ref_impl +return get_ref_impl(*this); +} + +/*! + @brief get a value (implicit) + + Implicit type conversion between the JSON value and a compatible value. + The call is realized by calling @ref get() const. + + @tparam ValueType non-pointer type compatible to the JSON value, for + instance `int` for JSON integer numbers, `bool` for JSON booleans, or + `std::vector` types for JSON arrays. The character type of @ref string_t + as well as an initializer list of this type is excluded to avoid + ambiguities as these types implicitly convert to `std::string`. + + @return copy of the JSON value, converted to type @a ValueType + + @throw type_error.302 in case passed type @a ValueType is incompatible + to the JSON value type (e.g., the JSON value is of type boolean, but a + string is requested); see example below + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,operator__ValueType} + + @since version 1.0.0 + */ +template < typename ValueType, typename std::enable_if < +not std::is_pointer::value and +not std::is_same>::value and +not std::is_same::value +#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 +and not std::is_same>::value +#endif +#if defined(JSON_HAS_CPP_17) +and not std::is_same::value +#endif +, int >::type = 0 > +operator ValueType() const +{ +// delegate the call to get<>() const +return get(); +} + +/// @} + + +//////////////////// +// element access // +//////////////////// + +/// @name element access +/// Access to the JSON value. +/// @{ + +/*! + @brief access specified array element with bounds checking + + Returns a reference to the element at specified location @a idx, with + bounds checking. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__size_type} + */ +reference at(size_type idx) +{ +// at only works for arrays +if (JSON_LIKELY(is_array())) +{ +JSON_TRY +{ +return m_value.array->at(idx); +} +JSON_CATCH (std::out_of_range&) +{ +// create better exception explanation +JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); +} +} +else +{ +JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); +} +} + +/*! + @brief access specified array element with bounds checking + + Returns a const reference to the element at specified location @a idx, + with bounds checking. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__size_type_const} + */ +const_reference at(size_type idx) const +{ +// at only works for arrays +if (JSON_LIKELY(is_array())) +{ +JSON_TRY +{ +return m_value.array->at(idx); +} +JSON_CATCH (std::out_of_range&) +{ +// create better exception explanation +JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); +} +} +else +{ +JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); +} +} + +/*! + @brief access specified object element with bounds checking + + Returns a reference to the element at with specified key @a key, with + bounds checking. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Logarithmic in the size of the container. + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__object_t_key_type} + */ +reference at(const typename object_t::key_type& key) +{ +// at only works for objects +if (JSON_LIKELY(is_object())) +{ +JSON_TRY +{ +return m_value.object->at(key); +} +JSON_CATCH (std::out_of_range&) +{ +// create better exception explanation +JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); +} +} +else +{ +JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); +} +} + +/*! + @brief access specified object element with bounds checking + + Returns a const reference to the element at with specified key @a key, + with bounds checking. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Logarithmic in the size of the container. + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__object_t_key_type_const} + */ +const_reference at(const typename object_t::key_type& key) const +{ +// at only works for objects +if (JSON_LIKELY(is_object())) +{ +JSON_TRY +{ +return m_value.object->at(key); +} +JSON_CATCH (std::out_of_range&) +{ +// create better exception explanation +JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); +} +} +else +{ +JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()))); +} +} + +/*! + @brief access specified array element + + Returns a reference to the element at specified location @a idx. + + @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), + then the array is silently filled up with `null` values to make `idx` a + valid reference to the last stored element. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw type_error.305 if the JSON value is not an array or null; in that + cases, using the [] operator with an index makes no sense. + + @complexity Constant if @a idx is in the range of the array. Otherwise + linear in `idx - size()`. + + @liveexample{The example below shows how array elements can be read and + written using `[]` operator. Note the addition of `null` + values.,operatorarray__size_type} + + @since version 1.0.0 + */ +reference operator[](size_type idx) +{ +// implicitly convert null value to an empty array +if (is_null()) +{ +m_type = value_t::array; +m_value.array = create(); +assert_invariant(); +} + +// operator[] only works for arrays +if (JSON_LIKELY(is_array())) +{ +// fill up array with null values if given idx is outside range +if (idx >= m_value.array->size()) +{ +m_value.array->insert(m_value.array->end(), +idx - m_value.array->size() + 1, +basic_json()); +} + +return m_value.array->operator[](idx); +} + +JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); +} + +/*! + @brief access specified array element + + Returns a const reference to the element at specified location @a idx. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw type_error.305 if the JSON value is not an array; in that case, + using the [] operator with an index makes no sense. + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read using + the `[]` operator.,operatorarray__size_type_const} + + @since version 1.0.0 + */ +const_reference operator[](size_type idx) const +{ +// const operator[] only works for arrays +if (JSON_LIKELY(is_array())) +{ +return m_value.array->operator[](idx); +} + +JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); +} + +/*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ +reference operator[](const typename object_t::key_type& key) +{ +// implicitly convert null value to an empty object +if (is_null()) +{ +m_type = value_t::object; +m_value.object = create(); +assert_invariant(); +} + +// operator[] only works for objects +if (JSON_LIKELY(is_object())) +{ +return m_value.object->operator[](key); +} + +JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); +} + +/*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw type_error.305 if the JSON value is not an object; in that case, + using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ +const_reference operator[](const typename object_t::key_type& key) const +{ +// const operator[] only works for objects +if (JSON_LIKELY(is_object())) +{ +assert(m_value.object->find(key) != m_value.object->end()); +return m_value.object->find(key)->second; +} + +JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); +} + +/*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ +template +reference operator[](T* key) +{ +// implicitly convert null to object +if (is_null()) +{ +m_type = value_t::object; +m_value = value_t::object; +assert_invariant(); +} + +// at only works for objects +if (JSON_LIKELY(is_object())) +{ +return m_value.object->operator[](key); +} + +JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); +} + +/*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw type_error.305 if the JSON value is not an object; in that case, + using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ +template +const_reference operator[](T* key) const +{ +// at only works for objects +if (JSON_LIKELY(is_object())) +{ +assert(m_value.object->find(key) != m_value.object->end()); +return m_value.object->find(key)->second; +} + +JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); +} + +/*! + @brief access specified object element with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(key); + } catch(out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const typename object_t::key_type&), this function + does not throw if the given key @a key was not found. + + @note Unlike @ref operator[](const typename object_t::key_type& key), this + function does not implicitly add an element to the position defined by @a + key. This function is furthermore also applicable to const objects. + + @param[in] key key of the element to access + @param[in] default_value the value to return if @a key is not found + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw type_error.306 if the JSON value is not an object; in that case, + using `value()` with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + + @since version 1.0.0 + */ +template::value, int>::type = 0> +ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const +{ +// at only works for objects +if (JSON_LIKELY(is_object())) +{ +// if key is found, return value and given default value otherwise +const auto it = find(key); +if (it != end()) +{ +return *it; +} + +return default_value; +} + +JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); +} + +/*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const + */ +string_t value(const typename object_t::key_type& key, const char* default_value) const +{ +return value(key, string_t(default_value)); +} + +/*! + @brief access specified object element via JSON Pointer with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(ptr); + } catch(out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const json_pointer&), this function does not throw + if the given key @a key was not found. + + @param[in] ptr a JSON pointer to the element to access + @param[in] default_value the value to return if @a ptr found no value + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw type_error.306 if the JSON value is not an objec; in that case, + using `value()` with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value_ptr} + + @sa @ref operator[](const json_pointer&) for unchecked access by reference + + @since version 2.0.2 + */ +template::value, int>::type = 0> +ValueType value(const json_pointer& ptr, const ValueType& default_value) const +{ +// at only works for objects +if (JSON_LIKELY(is_object())) +{ +// if pointer resolves a value, return it or use default value +JSON_TRY +{ +return ptr.get_checked(this); +} +JSON_CATCH (out_of_range&) +{ +return default_value; +} +} + +JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); +} + +/*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const json_pointer&, ValueType) const + */ +string_t value(const json_pointer& ptr, const char* default_value) const +{ +return value(ptr, string_t(default_value)); +} + +/*! + @brief access the first element + + Returns a reference to the first element in the container. For a JSON + container `c`, the expression `c.front()` is equivalent to `*c.begin()`. + + @return In case of a structured type (array or object), a reference to the + first element is returned. In case of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw invalid_iterator.214 when called on `null` value + + @liveexample{The following code shows an example for `front()`.,front} + + @sa @ref back() -- access the last element + + @since version 1.0.0 + */ +reference front() +{ +return *begin(); +} + +/*! + @copydoc basic_json::front() + */ +const_reference front() const +{ +return *cbegin(); +} + +/*! + @brief access the last element + + Returns a reference to the last element in the container. For a JSON + container `c`, the expression `c.back()` is equivalent to + @code {.cpp} + auto tmp = c.end(); + --tmp; + return *tmp; + @endcode + + @return In case of a structured type (array or object), a reference to the + last element is returned. In case of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw invalid_iterator.214 when called on a `null` value. See example + below. + + @liveexample{The following code shows an example for `back()`.,back} + + @sa @ref front() -- access the first element + + @since version 1.0.0 + */ +reference back() +{ +auto tmp = end(); +--tmp; +return *tmp; +} + +/*! + @copydoc basic_json::back() + */ +const_reference back() const +{ +auto tmp = cend(); +--tmp; +return *tmp; +} + +/*! + @brief remove element given an iterator + + Removes the element specified by iterator @a pos. The iterator @a pos must + be valid and dereferenceable. Thus the `end()` iterator (which is valid, + but is not dereferenceable) cannot be used as a value for @a pos. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] pos iterator to the element to remove + @return Iterator following the last removed element. If the iterator @a + pos refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.202 if called on an iterator which does not belong + to the current JSON value; example: `"iterator does not fit current + value"` + @throw invalid_iterator.205 if called on a primitive type with invalid + iterator (i.e., any iterator which is not `begin()`); example: `"iterator + out of range"` + + @complexity The complexity depends on the type: + - objects: amortized constant + - arrays: linear in distance between @a pos and the end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType} + + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ +template::value or +std::is_same::value, int>::type += 0> +IteratorType erase(IteratorType pos) +{ +// make sure iterator fits the current value +if (JSON_UNLIKELY(this != pos.m_object)) +{ +JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); +} + +IteratorType result = end(); + +switch (m_type) +{ +case value_t::boolean: +case value_t::number_float: +case value_t::number_integer: +case value_t::number_unsigned: +case value_t::string: +{ +if (JSON_UNLIKELY(not pos.m_it.primitive_iterator.is_begin())) +{ +JSON_THROW(invalid_iterator::create(205, "iterator out of range")); +} + +if (is_string()) +{ +AllocatorType alloc; +std::allocator_traits::destroy(alloc, m_value.string); +std::allocator_traits::deallocate(alloc, m_value.string, 1); +m_value.string = nullptr; +} + +m_type = value_t::null; +assert_invariant(); +break; +} + +case value_t::object: +{ +result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); +break; +} + +case value_t::array: +{ +result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); +break; +} + +default: +JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); +} + +return result; +} + +/*! + @brief remove elements given an iterator range + + Removes the element specified by the range `[first; last)`. The iterator + @a first does not need to be dereferenceable if `first == last`: erasing + an empty range is a no-op. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] first iterator to the beginning of the range to remove + @param[in] last iterator past the end of the range to remove + @return Iterator following the last removed element. If the iterator @a + second refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.203 if called on iterators which does not belong + to the current JSON value; example: `"iterators do not fit current value"` + @throw invalid_iterator.204 if called on a primitive type with invalid + iterators (i.e., if `first != begin()` and `last != end()`); example: + `"iterators out of range"` + + @complexity The complexity depends on the type: + - objects: `log(size()) + std::distance(first, last)` + - arrays: linear in the distance between @a first and @a last, plus linear + in the distance between @a last and end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType_IteratorType} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ +template::value or +std::is_same::value, int>::type += 0> +IteratorType erase(IteratorType first, IteratorType last) +{ +// make sure iterator fits the current value +if (JSON_UNLIKELY(this != first.m_object or this != last.m_object)) +{ +JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value")); +} + +IteratorType result = end(); + +switch (m_type) +{ +case value_t::boolean: +case value_t::number_float: +case value_t::number_integer: +case value_t::number_unsigned: +case value_t::string: +{ +if (JSON_LIKELY(not first.m_it.primitive_iterator.is_begin() +or not last.m_it.primitive_iterator.is_end())) +{ +JSON_THROW(invalid_iterator::create(204, "iterators out of range")); +} + +if (is_string()) +{ +AllocatorType alloc; +std::allocator_traits::destroy(alloc, m_value.string); +std::allocator_traits::deallocate(alloc, m_value.string, 1); +m_value.string = nullptr; +} + +m_type = value_t::null; +assert_invariant(); +break; +} + +case value_t::object: +{ +result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, +last.m_it.object_iterator); +break; +} + +case value_t::array: +{ +result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, +last.m_it.array_iterator); +break; +} + +default: +JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); +} + +return result; +} + +/*! + @brief remove element from a JSON object given a key + + Removes elements from a JSON object with the key value @a key. + + @param[in] key value of the elements to remove + + @return Number of elements removed. If @a ObjectType is the default + `std::map` type, the return value will always be `0` (@a key was not + found) or `1` (@a key was found). + + @post References and iterators to the erased elements are invalidated. + Other references and iterators are not affected. + + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` + + @complexity `log(size()) + count(key)` + + @liveexample{The example shows the effect of `erase()`.,erase__key_type} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ +size_type erase(const typename object_t::key_type& key) +{ +// this erase only works for objects +if (JSON_LIKELY(is_object())) +{ +return m_value.object->erase(key); +} + +JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); +} + +/*! + @brief remove element from a JSON array given an index + + Removes element from a JSON array at the index @a idx. + + @param[in] idx index of the element to remove + + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` + @throw out_of_range.401 when `idx >= size()`; example: `"array index 17 + is out of range"` + + @complexity Linear in distance between @a idx and the end of the container. + + @liveexample{The example shows the effect of `erase()`.,erase__size_type} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + + @since version 1.0.0 + */ +void erase(const size_type idx) +{ +// this erase only works for arrays +if (JSON_LIKELY(is_array())) +{ +if (JSON_UNLIKELY(idx >= size())) +{ +JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); +} + +m_value.array->erase(m_value.array->begin() + static_cast(idx)); +} +else +{ +JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()))); +} +} + +/// @} + + +//////////// +// lookup // +//////////// + +/// @name lookup +/// @{ + +/*! + @brief find an element in a JSON object + + Finds an element in a JSON object with key equivalent to @a key. If the + element is not found or the JSON value is not an object, end() is + returned. + + @note This method always returns @ref end() when executed on a JSON type + that is not an object. + + @param[in] key key value of the element to search for. + + @return Iterator to an element with key equivalent to @a key. If no such + element is found or the JSON value is not an object, past-the-end (see + @ref end()) iterator is returned. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `find()` is used.,find__key_type} + + @since version 1.0.0 + */ +template +iterator find(KeyT&& key) +{ +auto result = end(); + +if (is_object()) +{ +result.m_it.object_iterator = m_value.object->find(std::forward(key)); +} + +return result; +} + +/*! + @brief find an element in a JSON object + @copydoc find(KeyT&&) + */ +template +const_iterator find(KeyT&& key) const +{ +auto result = cend(); + +if (is_object()) +{ +result.m_it.object_iterator = m_value.object->find(std::forward(key)); +} + +return result; +} + +/*! + @brief returns the number of occurrences of a key in a JSON object + + Returns the number of elements with key @a key. If ObjectType is the + default `std::map` type, the return value will always be `0` (@a key was + not found) or `1` (@a key was found). + + @note This method always returns `0` when executed on a JSON type that is + not an object. + + @param[in] key key value of the element to count + + @return Number of elements with key @a key. If the JSON value is not an + object, the return value will be `0`. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `count()` is used.,count} + + @since version 1.0.0 + */ +template +size_type count(KeyT&& key) const +{ +// return 0 for all nonobject types +return is_object() ? m_value.object->count(std::forward(key)) : 0; +} + +/// @} + + +/////////////// +// iterators // +/////////////// + +/// @name iterators +/// @{ + +/*! + @brief returns an iterator to the first element + + Returns an iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `begin()`.,begin} + + @sa @ref cbegin() -- returns a const iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ +iterator begin() noexcept +{ +iterator result(this); +result.set_begin(); +return result; +} + +/*! + @copydoc basic_json::cbegin() + */ +const_iterator begin() const noexcept +{ +return cbegin(); +} + +/*! + @brief returns a const iterator to the first element + + Returns a const iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).begin()`. + + @liveexample{The following code shows an example for `cbegin()`.,cbegin} + + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ +const_iterator cbegin() const noexcept +{ +const_iterator result(this); +result.set_begin(); +return result; +} + +/*! + @brief returns an iterator to one past the last element + + Returns an iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `end()`.,end} + + @sa @ref cend() -- returns a const iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ +iterator end() noexcept +{ +iterator result(this); +result.set_end(); +return result; +} + +/*! + @copydoc basic_json::cend() + */ +const_iterator end() const noexcept +{ +return cend(); +} + +/*! + @brief returns a const iterator to one past the last element + + Returns a const iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).end()`. + + @liveexample{The following code shows an example for `cend()`.,cend} + + @sa @ref end() -- returns an iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ +const_iterator cend() const noexcept +{ +const_iterator result(this); +result.set_end(); +return result; +} + +/*! + @brief returns an iterator to the reverse-beginning + + Returns an iterator to the reverse-beginning; that is, the last element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(end())`. + + @liveexample{The following code shows an example for `rbegin()`.,rbegin} + + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ +reverse_iterator rbegin() noexcept +{ +return reverse_iterator(end()); +} + +/*! + @copydoc basic_json::crbegin() + */ +const_reverse_iterator rbegin() const noexcept +{ +return crbegin(); +} + +/*! + @brief returns an iterator to the reverse-end + + Returns an iterator to the reverse-end; that is, one before the first + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(begin())`. + + @liveexample{The following code shows an example for `rend()`.,rend} + + @sa @ref crend() -- returns a const reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ +reverse_iterator rend() noexcept +{ +return reverse_iterator(begin()); +} + +/*! + @copydoc basic_json::crend() + */ +const_reverse_iterator rend() const noexcept +{ +return crend(); +} + +/*! + @brief returns a const reverse iterator to the last element + + Returns a const iterator to the reverse-beginning; that is, the last + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rbegin()`. + + @liveexample{The following code shows an example for `crbegin()`.,crbegin} + + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ +const_reverse_iterator crbegin() const noexcept +{ +return const_reverse_iterator(cend()); +} + +/*! + @brief returns a const reverse iterator to one before the first + + Returns a const reverse iterator to the reverse-end; that is, one before + the first element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rend()`. + + @liveexample{The following code shows an example for `crend()`.,crend} + + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ +const_reverse_iterator crend() const noexcept +{ +return const_reverse_iterator(cbegin()); +} + +public: +/*! + @brief wrapper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + For loop without iterator_wrapper: + + @code{cpp} + for (auto it = j_object.begin(); it != j_object.end(); ++it) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + Range-based for loop without iterator proxy: + + @code{cpp} + for (auto it : j_object) + { + // "it" is of type json::reference and has no key() member + std::cout << "value: " << it << '\n'; + } + @endcode + + Range-based for loop with iterator proxy: + + @code{cpp} + for (auto it : json::iterator_wrapper(j_object)) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + @note When iterating over an array, `key()` will return the index of the + element as string (see example). + + @param[in] ref reference to a JSON value + @return iteration proxy object wrapping @a ref with an interface to use in + range-based for loops + + @liveexample{The following code shows how the wrapper is used,iterator_wrapper} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @note The name of this function is not yet final and may change in the + future. + + @deprecated This stream operator is deprecated and will be removed in + future 4.0.0 of the library. Please use @ref items() instead; + that is, replace `json::iterator_wrapper(j)` with `j.items()`. + */ +JSON_DEPRECATED +static iteration_proxy iterator_wrapper(reference ref) noexcept +{ +return ref.items(); +} + +/*! + @copydoc iterator_wrapper(reference) + */ +JSON_DEPRECATED +static iteration_proxy iterator_wrapper(const_reference ref) noexcept +{ +return ref.items(); +} + +/*! + @brief helper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + For loop without `items()` function: + + @code{cpp} + for (auto it = j_object.begin(); it != j_object.end(); ++it) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + Range-based for loop without `items()` function: + + @code{cpp} + for (auto it : j_object) + { + // "it" is of type json::reference and has no key() member + std::cout << "value: " << it << '\n'; + } + @endcode + + Range-based for loop with `items()` function: + + @code{cpp} + for (auto it : j_object.items()) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + @note When iterating over an array, `key()` will return the index of the + element as string (see example). For primitive types (e.g., numbers), + `key()` returns an empty string. + + @return iteration proxy object wrapping @a ref with an interface to use in + range-based for loops + + @liveexample{The following code shows how the function is used.,items} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 3.x.x. + */ +iteration_proxy items() noexcept +{ +return iteration_proxy(*this); +} + +/*! + @copydoc items() + */ +iteration_proxy items() const noexcept +{ +return iteration_proxy(*this); +} + +/// @} + + +////////////// +// capacity // +////////////// + +/// @name capacity +/// @{ + +/*! + @brief checks whether the container is empty. + + Checks if a JSON value has no elements (i.e. whether its @ref size is `0`). + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `true` + boolean | `false` + string | `false` + number | `false` + object | result of function `object_t::empty()` + array | result of function `array_t::empty()` + + @liveexample{The following code uses `empty()` to check if a JSON + object contains any elements.,empty} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `empty()` functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return whether a string stored as JSON value + is empty - it returns whether the JSON container itself is empty which is + false in the case of a string. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `begin() == end()`. + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ +bool empty() const noexcept +{ +switch (m_type) +{ +case value_t::null: +{ +// null values are empty +return true; +} + +case value_t::array: +{ +// delegate call to array_t::empty() +return m_value.array->empty(); +} + +case value_t::object: +{ +// delegate call to object_t::empty() +return m_value.object->empty(); +} + +default: +{ +// all other types are nonempty +return false; +} +} +} + +/*! + @brief returns the number of elements + + Returns the number of elements in a JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` + boolean | `1` + string | `1` + number | `1` + object | result of function object_t::size() + array | result of function array_t::size() + + @liveexample{The following code calls `size()` on the different value + types.,size} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their size() functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return the length of a string stored as JSON + value - it returns the number of elements in the JSON value which is 1 in + the case of a string. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `std::distance(begin(), end())`. + + @sa @ref empty() -- checks whether the container is empty + @sa @ref max_size() -- returns the maximal number of elements + + @since version 1.0.0 + */ +size_type size() const noexcept +{ +switch (m_type) +{ +case value_t::null: +{ +// null values are empty +return 0; +} + +case value_t::array: +{ +// delegate call to array_t::size() +return m_value.array->size(); +} + +case value_t::object: +{ +// delegate call to object_t::size() +return m_value.object->size(); +} + +default: +{ +// all other types have size 1 +return 1; +} +} +} + +/*! + @brief returns the maximum possible number of elements + + Returns the maximum number of elements a JSON value is able to hold due to + system or library implementation limitations, i.e. `std::distance(begin(), + end())` for the JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` (same as `size()`) + boolean | `1` (same as `size()`) + string | `1` (same as `size()`) + number | `1` (same as `size()`) + object | result of function `object_t::max_size()` + array | result of function `array_t::max_size()` + + @liveexample{The following code calls `max_size()` on the different value + types. Note the output is implementation specific.,max_size} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `max_size()` functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of returning `b.size()` where `b` is the largest + possible JSON value. + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ +size_type max_size() const noexcept +{ +switch (m_type) +{ +case value_t::array: +{ +// delegate call to array_t::max_size() +return m_value.array->max_size(); +} + +case value_t::object: +{ +// delegate call to object_t::max_size() +return m_value.object->max_size(); +} + +default: +{ +// all other types have max_size() == size() +return size(); +} +} +} + +/// @} + + +/////////////// +// modifiers // +/////////////// + +/// @name modifiers +/// @{ + +/*! + @brief clears the contents + + Clears the content of a JSON value and resets it to the default value as + if @ref basic_json(value_t) would have been called with the current value + type from @ref type(): + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @post Has the same effect as calling + @code {.cpp} + *this = basic_json(type()); + @endcode + + @liveexample{The example below shows the effect of `clear()` to different + JSON types.,clear} + + @complexity Linear in the size of the JSON value. + + @iterators All iterators, pointers and references related to this container + are invalidated. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @sa @ref basic_json(value_t) -- constructor that creates an object with the + same value than calling `clear()` + + @since version 1.0.0 + */ +void clear() noexcept +{ +switch (m_type) +{ +case value_t::number_integer: +{ +m_value.number_integer = 0; +break; +} + +case value_t::number_unsigned: +{ +m_value.number_unsigned = 0; +break; +} + +case value_t::number_float: +{ +m_value.number_float = 0.0; +break; +} + +case value_t::boolean: +{ +m_value.boolean = false; +break; +} + +case value_t::string: +{ +m_value.string->clear(); +break; +} + +case value_t::array: +{ +m_value.array->clear(); +break; +} + +case value_t::object: +{ +m_value.object->clear(); +break; +} + +default: +break; +} +} + +/*! + @brief add an object to an array + + Appends the given element @a val to the end of the JSON value. If the + function is called on a JSON null value, an empty array is created before + appending @a val. + + @param[in] val the value to add to the JSON array + + @throw type_error.308 when called on a type other than JSON array or + null; example: `"cannot use push_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON array. Note how the `null` value was silently + converted to a JSON array.,push_back} + + @since version 1.0.0 + */ +void push_back(basic_json&& val) +{ +// push_back only works for null objects or arrays +if (JSON_UNLIKELY(not(is_null() or is_array()))) +{ +JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); +} + +// transform null object into an array +if (is_null()) +{ +m_type = value_t::array; +m_value = value_t::array; +assert_invariant(); +} + +// add element to array (move semantics) +m_value.array->push_back(std::move(val)); +// invalidate object +val.m_type = value_t::null; +} + +/*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ +reference operator+=(basic_json&& val) +{ +push_back(std::move(val)); +return *this; +} + +/*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ +void push_back(const basic_json& val) +{ +// push_back only works for null objects or arrays +if (JSON_UNLIKELY(not(is_null() or is_array()))) +{ +JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); +} + +// transform null object into an array +if (is_null()) +{ +m_type = value_t::array; +m_value = value_t::array; +assert_invariant(); +} + +// add element to array +m_value.array->push_back(val); +} + +/*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ +reference operator+=(const basic_json& val) +{ +push_back(val); +return *this; +} + +/*! + @brief add an object to an object + + Inserts the given element @a val to the JSON object. If the function is + called on a JSON null value, an empty object is created before inserting + @a val. + + @param[in] val the value to add to the JSON object + + @throw type_error.308 when called on a type other than JSON object or + null; example: `"cannot use push_back() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON object. Note how the `null` value was silently + converted to a JSON object.,push_back__object_t__value} + + @since version 1.0.0 + */ +void push_back(const typename object_t::value_type& val) +{ +// push_back only works for null objects or objects +if (JSON_UNLIKELY(not(is_null() or is_object()))) +{ +JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); +} + +// transform null object into an object +if (is_null()) +{ +m_type = value_t::object; +m_value = value_t::object; +assert_invariant(); +} + +// add element to array +m_value.object->insert(val); +} + +/*! + @brief add an object to an object + @copydoc push_back(const typename object_t::value_type&) + */ +reference operator+=(const typename object_t::value_type& val) +{ +push_back(val); +return *this; +} + +/*! + @brief add an object to an object + + This function allows to use `push_back` with an initializer list. In case + + 1. the current value is an object, + 2. the initializer list @a init contains only two elements, and + 3. the first element of @a init is a string, + + @a init is converted into an object element and added using + @ref push_back(const typename object_t::value_type&). Otherwise, @a init + is converted to a JSON value and added using @ref push_back(basic_json&&). + + @param[in] init an initializer list + + @complexity Linear in the size of the initializer list @a init. + + @note This function is required to resolve an ambiguous overload error, + because pairs like `{"key", "value"}` can be both interpreted as + `object_t::value_type` or `std::initializer_list`, see + https://github.com/nlohmann/json/issues/235 for more information. + + @liveexample{The example shows how initializer lists are treated as + objects when possible.,push_back__initializer_list} + */ +void push_back(initializer_list_t init) +{ +if (is_object() and init.size() == 2 and (*init.begin())->is_string()) +{ +basic_json&& key = init.begin()->moved_or_copied(); +push_back(typename object_t::value_type( +std::move(key.get_ref()), (init.begin() + 1)->moved_or_copied())); +} +else +{ +push_back(basic_json(init)); +} +} + +/*! + @brief add an object to an object + @copydoc push_back(initializer_list_t) + */ +reference operator+=(initializer_list_t init) +{ +push_back(init); +return *this; +} + +/*! + @brief add an object to an array + + Creates a JSON value from the passed parameters @a args to the end of the + JSON value. If the function is called on a JSON null value, an empty array + is created before appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @throw type_error.311 when called on a type other than JSON array or + null; example: `"cannot use emplace_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` can be used to add + elements to a JSON array. Note how the `null` value was silently converted + to a JSON array.,emplace_back} + + @since version 2.0.8 + */ +template +void emplace_back(Args&& ... args) +{ +// emplace_back only works for null objects or arrays +if (JSON_UNLIKELY(not(is_null() or is_array()))) +{ +JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name()))); +} + +// transform null object into an array +if (is_null()) +{ +m_type = value_t::array; +m_value = value_t::array; +assert_invariant(); +} + +// add element to array (perfect forwarding) +m_value.array->emplace_back(std::forward(args)...); +} + +/*! + @brief add an object to an object if key does not exist + + Inserts a new element into a JSON object constructed in-place with the + given @a args if there is no element with the key in the container. If the + function is called on a JSON null value, an empty object is created before + appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @return a pair consisting of an iterator to the inserted element, or the + already-existing element if no insertion happened, and a bool + denoting whether the insertion took place. + + @throw type_error.311 when called on a type other than JSON object or + null; example: `"cannot use emplace() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `emplace()` can be used to add elements + to a JSON object. Note how the `null` value was silently converted to a + JSON object. Further note how no value is added if there was already one + value stored with the same key.,emplace} + + @since version 2.0.8 + */ +template +std::pair emplace(Args&& ... args) +{ +// emplace only works for null objects or arrays +if (JSON_UNLIKELY(not(is_null() or is_object()))) +{ +JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name()))); +} + +// transform null object into an object +if (is_null()) +{ +m_type = value_t::object; +m_value = value_t::object; +assert_invariant(); +} + +// add element to array (perfect forwarding) +auto res = m_value.object->emplace(std::forward(args)...); +// create result iterator and set iterator to the result of emplace +auto it = begin(); +it.m_it.object_iterator = res.first; + +// return pair of iterator and boolean +return {it, res.second}; +} + +/*! + @brief inserts element + + Inserts element @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] val element to insert + @return iterator pointing to the inserted @a val. + + @throw type_error.309 if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @complexity Constant plus linear in the distance between @a pos and end of + the container. + + @liveexample{The example shows how `insert()` is used.,insert} + + @since version 1.0.0 + */ +iterator insert(const_iterator pos, const basic_json& val) +{ +// insert only works for arrays +if (JSON_LIKELY(is_array())) +{ +// check if iterator pos fits to this JSON value +if (JSON_UNLIKELY(pos.m_object != this)) +{ +JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); +} + +// insert to array and return iterator +iterator result(this); +result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); +return result; +} + +JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); +} + +/*! + @brief inserts element + @copydoc insert(const_iterator, const basic_json&) + */ +iterator insert(const_iterator pos, basic_json&& val) +{ +return insert(pos, val); +} + +/*! + @brief inserts elements + + Inserts @a cnt copies of @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] cnt number of copies of @a val to insert + @param[in] val element to insert + @return iterator pointing to the first element inserted, or @a pos if + `cnt==0` + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @complexity Linear in @a cnt plus linear in the distance between @a pos + and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__count} + + @since version 1.0.0 + */ +iterator insert(const_iterator pos, size_type cnt, const basic_json& val) +{ +// insert only works for arrays +if (JSON_LIKELY(is_array())) +{ +// check if iterator pos fits to this JSON value +if (JSON_UNLIKELY(pos.m_object != this)) +{ +JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); +} + +// insert to array and return iterator +iterator result(this); +result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); +return result; +} + +JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); +} + +/*! + @brief inserts elements + + Inserts elements from range `[first, last)` before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + @throw invalid_iterator.211 if @a first or @a last are iterators into + container for which insert is called; example: `"passed iterators may not + belong to container"` + + @return iterator pointing to the first element inserted, or @a pos if + `first==last` + + @complexity Linear in `std::distance(first, last)` plus linear in the + distance between @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__range} + + @since version 1.0.0 + */ +iterator insert(const_iterator pos, const_iterator first, const_iterator last) +{ +// insert only works for arrays +if (JSON_UNLIKELY(not is_array())) +{ +JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); +} + +// check if iterator pos fits to this JSON value +if (JSON_UNLIKELY(pos.m_object != this)) +{ +JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); +} + +// check if range iterators belong to the same JSON object +if (JSON_UNLIKELY(first.m_object != last.m_object)) +{ +JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); +} + +if (JSON_UNLIKELY(first.m_object == this)) +{ +JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container")); +} + +// insert to array and return iterator +iterator result(this); +result.m_it.array_iterator = m_value.array->insert( +pos.m_it.array_iterator, +first.m_it.array_iterator, +last.m_it.array_iterator); +return result; +} + +/*! + @brief inserts elements + + Inserts elements from initializer list @a ilist before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] ilist initializer list to insert the values from + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @return iterator pointing to the first element inserted, or @a pos if + `ilist` is empty + + @complexity Linear in `ilist.size()` plus linear in the distance between + @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__ilist} + + @since version 1.0.0 + */ +iterator insert(const_iterator pos, initializer_list_t ilist) +{ +// insert only works for arrays +if (JSON_UNLIKELY(not is_array())) +{ +JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); +} + +// check if iterator pos fits to this JSON value +if (JSON_UNLIKELY(pos.m_object != this)) +{ +JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); +} + +// insert to array and return iterator +iterator result(this); +result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist.begin(), ilist.end()); +return result; +} + +/*! + @brief inserts elements + + Inserts elements from range `[first, last)`. + + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.309 if called on JSON values other than objects; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if iterator @a first or @a last does does not + point to an object; example: `"iterators first and last must point to + objects"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + + @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number + of elements to insert. + + @liveexample{The example shows how `insert()` is used.,insert__range_object} + + @since version 3.0.0 + */ +void insert(const_iterator first, const_iterator last) +{ +// insert only works for objects +if (JSON_UNLIKELY(not is_object())) +{ +JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); +} + +// check if range iterators belong to the same JSON object +if (JSON_UNLIKELY(first.m_object != last.m_object)) +{ +JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); +} + +// passed iterators must belong to objects +if (JSON_UNLIKELY(not first.m_object->is_object())) +{ +JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); +} + +m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); +} + +/*! + @brief updates a JSON object from another object, overwriting existing keys + + Inserts all values from JSON object @a j and overwrites existing keys. + + @param[in] j JSON object to read values from + + @throw type_error.312 if called on JSON values other than objects; example: + `"cannot use update() with string"` + + @complexity O(N*log(size() + N)), where N is the number of elements to + insert. + + @liveexample{The example shows how `update()` is used.,update} + + @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update + + @since version 3.0.0 + */ +void update(const_reference j) +{ +// implicitly convert null value to an empty object +if (is_null()) +{ +m_type = value_t::object; +m_value.object = create(); +assert_invariant(); +} + +if (JSON_UNLIKELY(not is_object())) +{ +JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); +} +if (JSON_UNLIKELY(not j.is_object())) +{ +JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()))); +} + +for (auto it = j.cbegin(); it != j.cend(); ++it) +{ +m_value.object->operator[](it.key()) = it.value(); +} +} + +/*! + @brief updates a JSON object from another object, overwriting existing keys + + Inserts all values from from range `[first, last)` and overwrites existing + keys. + + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.312 if called on JSON values other than objects; example: + `"cannot use update() with string"` + @throw invalid_iterator.202 if iterator @a first or @a last does does not + point to an object; example: `"iterators first and last must point to + objects"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + + @complexity O(N*log(size() + N)), where N is the number of elements to + insert. + + @liveexample{The example shows how `update()` is used__range.,update} + + @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update + + @since version 3.0.0 + */ +void update(const_iterator first, const_iterator last) +{ +// implicitly convert null value to an empty object +if (is_null()) +{ +m_type = value_t::object; +m_value.object = create(); +assert_invariant(); +} + +if (JSON_UNLIKELY(not is_object())) +{ +JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); +} + +// check if range iterators belong to the same JSON object +if (JSON_UNLIKELY(first.m_object != last.m_object)) +{ +JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); +} + +// passed iterators must belong to objects +if (JSON_UNLIKELY(not first.m_object->is_object() +or not first.m_object->is_object())) +{ +JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); +} + +for (auto it = first; it != last; ++it) +{ +m_value.object->operator[](it.key()) = it.value(); +} +} + +/*! + @brief exchanges the values + + Exchanges the contents of the JSON value with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other JSON value to exchange the contents with + + @complexity Constant. + + @liveexample{The example below shows how JSON values can be swapped with + `swap()`.,swap__reference} + + @since version 1.0.0 + */ +void swap(reference other) noexcept ( +std::is_nothrow_move_constructible::value and +std::is_nothrow_move_assignable::value and +std::is_nothrow_move_constructible::value and +std::is_nothrow_move_assignable::value +) +{ +std::swap(m_type, other.m_type); +std::swap(m_value, other.m_value); +assert_invariant(); +} + +/*! + @brief exchanges the values + + Exchanges the contents of a JSON array with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other array to exchange the contents with + + @throw type_error.310 when JSON value is not an array; example: `"cannot + use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how arrays can be swapped with + `swap()`.,swap__array_t} + + @since version 1.0.0 + */ +void swap(array_t& other) +{ +// swap only works for arrays +if (JSON_LIKELY(is_array())) +{ +std::swap(*(m_value.array), other); +} +else +{ +JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); +} +} + +/*! + @brief exchanges the values + + Exchanges the contents of a JSON object with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other object to exchange the contents with + + @throw type_error.310 when JSON value is not an object; example: + `"cannot use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how objects can be swapped with + `swap()`.,swap__object_t} + + @since version 1.0.0 + */ +void swap(object_t& other) +{ +// swap only works for objects +if (JSON_LIKELY(is_object())) +{ +std::swap(*(m_value.object), other); +} +else +{ +JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); +} +} + +/*! + @brief exchanges the values + + Exchanges the contents of a JSON string with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other string to exchange the contents with + + @throw type_error.310 when JSON value is not a string; example: `"cannot + use swap() with boolean"` + + @complexity Constant. + + @liveexample{The example below shows how strings can be swapped with + `swap()`.,swap__string_t} + + @since version 1.0.0 + */ +void swap(string_t& other) +{ +// swap only works for strings +if (JSON_LIKELY(is_string())) +{ +std::swap(*(m_value.string), other); +} +else +{ +JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); +} +} + +/// @} + +public: +////////////////////////////////////////// +// lexicographical comparison operators // +////////////////////////////////////////// + +/// @name lexicographical comparison operators +/// @{ + +/*! + @brief comparison: equal + + Compares two JSON values for equality according to the following rules: + - Two JSON values are equal if (1) they are from the same type and (2) + their stored values are the same according to their respective + `operator==`. + - Integer and floating-point numbers are automatically converted before + comparison. Note than two NaN values are always treated as unequal. + - Two JSON null values are equal. + + @note Floating-point inside JSON values numbers are compared with + `json::number_float_t::operator==` which is `double::operator==` by + default. To compare floating-point while respecting an epsilon, an alternative + [comparison function](https://github.com/mariokonrad/marnav/blob/master/src/marnav/math/floatingpoint.hpp#L34-#L39) + could be used, for instance + @code {.cpp} + template::value, T>::type> + inline bool is_same(T a, T b, T epsilon = std::numeric_limits::epsilon()) noexcept + { + return std::abs(a - b) <= epsilon; + } + @endcode + + @note NaN values never compare equal to themselves or to other NaN values. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are equal + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__equal} + + @since version 1.0.0 + */ +friend bool operator==(const_reference lhs, const_reference rhs) noexcept +{ +const auto lhs_type = lhs.type(); +const auto rhs_type = rhs.type(); + +if (lhs_type == rhs_type) +{ +switch (lhs_type) +{ +case value_t::array: +return (*lhs.m_value.array == *rhs.m_value.array); + +case value_t::object: +return (*lhs.m_value.object == *rhs.m_value.object); + +case value_t::null: +return true; + +case value_t::string: +return (*lhs.m_value.string == *rhs.m_value.string); + +case value_t::boolean: +return (lhs.m_value.boolean == rhs.m_value.boolean); + +case value_t::number_integer: +return (lhs.m_value.number_integer == rhs.m_value.number_integer); + +case value_t::number_unsigned: +return (lhs.m_value.number_unsigned == rhs.m_value.number_unsigned); + +case value_t::number_float: +return (lhs.m_value.number_float == rhs.m_value.number_float); + +default: +return false; +} +} +else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) +{ +return (static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float); +} +else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) +{ +return (lhs.m_value.number_float == static_cast(rhs.m_value.number_integer)); +} +else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) +{ +return (static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float); +} +else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) +{ +return (lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned)); +} +else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) +{ +return (static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer); +} +else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) +{ +return (lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned)); +} + +return false; +} + +/*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept +{ +return (lhs == basic_json(rhs)); +} + +/*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept +{ +return (basic_json(lhs) == rhs); +} + +/*! + @brief comparison: not equal + + Compares two JSON values for inequality by calculating `not (lhs == rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are not equal + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__notequal} + + @since version 1.0.0 + */ +friend bool operator!=(const_reference lhs, const_reference rhs) noexcept +{ +return not (lhs == rhs); +} + +/*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept +{ +return (lhs != basic_json(rhs)); +} + +/*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept +{ +return (basic_json(lhs) != rhs); +} + +/*! + @brief comparison: less than + + Compares whether one JSON value @a lhs is less than another JSON value @a + rhs according to the following rules: + - If @a lhs and @a rhs have the same type, the values are compared using + the default `<` operator. + - Integer and floating-point numbers are automatically converted before + comparison + - In case @a lhs and @a rhs have different types, the values are ignored + and the order of the types is considered, see + @ref operator<(const value_t, const value_t). + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__less} + + @since version 1.0.0 + */ +friend bool operator<(const_reference lhs, const_reference rhs) noexcept +{ +const auto lhs_type = lhs.type(); +const auto rhs_type = rhs.type(); + +if (lhs_type == rhs_type) +{ +switch (lhs_type) +{ +case value_t::array: +return (*lhs.m_value.array) < (*rhs.m_value.array); + +case value_t::object: +return *lhs.m_value.object < *rhs.m_value.object; + +case value_t::null: +return false; + +case value_t::string: +return *lhs.m_value.string < *rhs.m_value.string; + +case value_t::boolean: +return lhs.m_value.boolean < rhs.m_value.boolean; + +case value_t::number_integer: +return lhs.m_value.number_integer < rhs.m_value.number_integer; + +case value_t::number_unsigned: +return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; + +case value_t::number_float: +return lhs.m_value.number_float < rhs.m_value.number_float; + +default: +return false; +} +} +else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) +{ +return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; +} +else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) +{ +return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); +} +else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) +{ +return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; +} +else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) +{ +return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); +} +else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) +{ +return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); +} +else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) +{ +return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; +} + +// We only reach this line if we cannot compare values. In that case, +// we compare types. Note we have to call the operator explicitly, +// because MSVC has problems otherwise. +return operator<(lhs_type, rhs_type); +} + +/*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept +{ +return (lhs < basic_json(rhs)); +} + +/*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept +{ +return (basic_json(lhs) < rhs); +} + +/*! + @brief comparison: less than or equal + + Compares whether one JSON value @a lhs is less than or equal to another + JSON value by calculating `not (rhs < lhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than or equal to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greater} + + @since version 1.0.0 + */ +friend bool operator<=(const_reference lhs, const_reference rhs) noexcept +{ +return not (rhs < lhs); +} + +/*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept +{ +return (lhs <= basic_json(rhs)); +} + +/*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept +{ +return (basic_json(lhs) <= rhs); +} + +/*! + @brief comparison: greater than + + Compares whether one JSON value @a lhs is greater than another + JSON value by calculating `not (lhs <= rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__lessequal} + + @since version 1.0.0 + */ +friend bool operator>(const_reference lhs, const_reference rhs) noexcept +{ +return not (lhs <= rhs); +} + +/*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept +{ +return (lhs > basic_json(rhs)); +} + +/*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept +{ +return (basic_json(lhs) > rhs); +} + +/*! + @brief comparison: greater than or equal + + Compares whether one JSON value @a lhs is greater than or equal to another + JSON value by calculating `not (lhs < rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than or equal to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greaterequal} + + @since version 1.0.0 + */ +friend bool operator>=(const_reference lhs, const_reference rhs) noexcept +{ +return not (lhs < rhs); +} + +/*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept +{ +return (lhs >= basic_json(rhs)); +} + +/*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ +template::value, int>::type = 0> +friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept +{ +return (basic_json(lhs) >= rhs); +} + +/// @} + +/////////////////// +// serialization // +/////////////////// + +/// @name serialization +/// @{ + +/*! + @brief serialize to stream + + Serialize the given JSON value @a j to the output stream @a o. The JSON + value will be serialized using the @ref dump member function. + + - The indentation of the output can be controlled with the member variable + `width` of the output stream @a o. For instance, using the manipulator + `std::setw(4)` on @a o sets the indentation level to `4` and the + serialization result is the same as calling `dump(4)`. + + - The indentation character can be controlled with the member variable + `fill` of the output stream @a o. For instance, the manipulator + `std::setfill('\\t')` sets indentation to use a tab character rather than + the default space character. + + @param[in,out] o stream to serialize to + @param[in] j JSON value to serialize + + @return the stream @a o + + @throw type_error.316 if a string stored inside the JSON value is not + UTF-8 encoded + + @complexity Linear. + + @liveexample{The example below shows the serialization with different + parameters to `width` to adjust the indentation level.,operator_serialize} + + @since version 1.0.0; indentation character added in version 3.0.0 + */ +friend std::ostream& operator<<(std::ostream& o, const basic_json& j) +{ +// read width member and use it as indentation parameter if nonzero +const bool pretty_print = (o.width() > 0); +const auto indentation = (pretty_print ? o.width() : 0); + +// reset width to 0 for subsequent calls to this stream +o.width(0); + +// do the actual serialization +serializer s(detail::output_adapter(o), o.fill()); +s.dump(j, pretty_print, false, static_cast(indentation)); +return o; +} + +/*! + @brief serialize to stream + @deprecated This stream operator is deprecated and will be removed in + future 4.0.0 of the library. Please use + @ref operator<<(std::ostream&, const basic_json&) + instead; that is, replace calls like `j >> o;` with `o << j;`. + @since version 1.0.0; deprecated since version 3.0.0 + */ +JSON_DEPRECATED +friend std::ostream& operator>>(const basic_json& j, std::ostream& o) +{ +return o << j; +} + +/// @} + + +///////////////////// +// deserialization // +///////////////////// + +/// @name deserialization +/// @{ + +/*! + @brief deserialize from a compatible input + + This function reads from a compatible input. Examples are: + - an array of 1-byte values + - strings with character/literal type with size of 1 byte + - input streams + - container with contiguous storage of 1-byte values. Compatible container + types include `std::vector`, `std::string`, `std::array`, + `std::valarray`, and `std::initializer_list`. Furthermore, C-style + arrays can be used with `std::begin()`/`std::end()`. User-defined + containers can be used as long as they implement random-access iterators + and a contiguous storage. + + @pre Each element of the container has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @pre The container storage is contiguous. Violating this precondition + yields undefined behavior. **This precondition is enforced with an + assertion.** + @pre Each element of the container has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @warning There is no way to enforce all preconditions at compile-time. If + the function is called with a noncompliant container and with + assertions switched off, the behavior is undefined and will most + likely yield segmentation violation. + + @param[in] i input to read from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from an array.,parse__array__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__string__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__istream__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function reading + from a contiguous container.,parse__contiguouscontainer__parser_callback_t} + + @since version 2.0.3 (contiguous containers) + */ +static basic_json parse(detail::input_adapter i, +const parser_callback_t cb = nullptr, +const bool allow_exceptions = true) +{ +basic_json result; +parser(i, cb, allow_exceptions).parse(true, result); +return result; +} + +/*! + @copydoc basic_json parse(detail::input_adapter, const parser_callback_t) + */ +static basic_json parse(detail::input_adapter& i, +const parser_callback_t cb = nullptr, +const bool allow_exceptions = true) +{ +basic_json result; +parser(i, cb, allow_exceptions).parse(true, result); +return result; +} + +static bool accept(detail::input_adapter i) +{ +return parser(i).accept(true); +} + +static bool accept(detail::input_adapter& i) +{ +return parser(i).accept(true); +} + +/*! + @brief deserialize from an iterator range with contiguous storage + + This function reads from an iterator range of a container with contiguous + storage of 1-byte values. Compatible container types include + `std::vector`, `std::string`, `std::array`, `std::valarray`, and + `std::initializer_list`. Furthermore, C-style arrays can be used with + `std::begin()`/`std::end()`. User-defined containers can be used as long + as they implement random-access iterators and a contiguous storage. + + @pre The iterator range is contiguous. Violating this precondition yields + undefined behavior. **This precondition is enforced with an assertion.** + @pre Each element in the range has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @warning There is no way to enforce all preconditions at compile-time. If + the function is called with noncompliant iterators and with + assertions switched off, the behavior is undefined and will most + likely yield segmentation violation. + + @tparam IteratorType iterator of container with contiguous storage + @param[in] first begin of the range to parse (included) + @param[in] last end of the range to parse (excluded) + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + + @return result of the deserialization + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from an iterator range.,parse__iteratortype__parser_callback_t} + + @since version 2.0.3 + */ +template::iterator_category>::value, int>::type = 0> +static basic_json parse(IteratorType first, IteratorType last, +const parser_callback_t cb = nullptr, +const bool allow_exceptions = true) +{ +basic_json result; +parser(detail::input_adapter(first, last), cb, allow_exceptions).parse(true, result); +return result; +} + +template::iterator_category>::value, int>::type = 0> +static bool accept(IteratorType first, IteratorType last) +{ +return parser(detail::input_adapter(first, last)).accept(true); +} + +/*! + @brief deserialize from stream + @deprecated This stream operator is deprecated and will be removed in + version 4.0.0 of the library. Please use + @ref operator>>(std::istream&, basic_json&) + instead; that is, replace calls like `j << i;` with `i >> j;`. + @since version 1.0.0; deprecated since version 3.0.0 + */ +JSON_DEPRECATED +friend std::istream& operator<<(basic_json& j, std::istream& i) +{ +return operator>>(i, j); +} + +/*! + @brief deserialize from stream + + Deserializes an input stream to a JSON value. + + @param[in,out] i input stream to read a serialized JSON value from + @param[in,out] j JSON value to write the deserialized input to + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below shows how a JSON value is constructed by + reading a serialization from a stream.,operator_deserialize} + + @sa parse(std::istream&, const parser_callback_t) for a variant with a + parser callback function to filter values while parsing + + @since version 1.0.0 + */ +friend std::istream& operator>>(std::istream& i, basic_json& j) +{ +parser(detail::input_adapter(i)).parse(false, j); +return i; +} + +/// @} + +/////////////////////////// +// convenience functions // +/////////////////////////// + +/*! + @brief return the type as string + + Returns the type name as string to be used in error messages - usually to + indicate that a function was called on a wrong JSON type. + + @return a string representation of a the @a m_type member: + Value type | return value + ----------- | ------------- + null | `"null"` + boolean | `"boolean"` + string | `"string"` + number | `"number"` (for all number types) + object | `"object"` + array | `"array"` + discarded | `"discarded"` + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @complexity Constant. + + @liveexample{The following code exemplifies `type_name()` for all JSON + types.,type_name} + + @sa @ref type() -- return the type of the JSON value + @sa @ref operator value_t() -- return the type of the JSON value (implicit) + + @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept` + since 3.0.0 + */ +const char* type_name() const noexcept +{ +{ +switch (m_type) +{ +case value_t::null: +return "null"; +case value_t::object: +return "object"; +case value_t::array: +return "array"; +case value_t::string: +return "string"; +case value_t::boolean: +return "boolean"; +case value_t::discarded: +return "discarded"; +default: +return "number"; +} +} +} + + +private: +////////////////////// +// member variables // +////////////////////// + +/// the type of the current element +value_t m_type = value_t::null; + +/// the value of the current element +json_value m_value = {}; + +////////////////////////////////////////// +// binary serialization/deserialization // +////////////////////////////////////////// + +/// @name binary serialization/deserialization support +/// @{ + +public: +/*! + @brief create a CBOR serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the CBOR (Concise + Binary Object Representation) serialization format. CBOR is a binary + serialization format which aims to be more compact than JSON itself, yet + more efficient to parse. + + The library uses the following mapping from JSON values types to + CBOR types according to the CBOR specification (RFC 7049): + + JSON value type | value/range | CBOR type | first byte + --------------- | ------------------------------------------ | ---------------------------------- | --------------- + null | `null` | Null | 0xF6 + boolean | `true` | True | 0xF5 + boolean | `false` | False | 0xF4 + number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3B + number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3A + number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39 + number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38 + number_integer | -24..-1 | Negative integer | 0x20..0x37 + number_integer | 0..23 | Integer | 0x00..0x17 + number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B + number_unsigned | 0..23 | Integer | 0x00..0x17 + number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B + number_float | *any value* | Double-Precision Float | 0xFB + string | *length*: 0..23 | UTF-8 string | 0x60..0x77 + string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78 + string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79 + string | *length*: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7A + string | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7B + array | *size*: 0..23 | array | 0x80..0x97 + array | *size*: 23..255 | array (1 byte follow) | 0x98 + array | *size*: 256..65535 | array (2 bytes follow) | 0x99 + array | *size*: 65536..4294967295 | array (4 bytes follow) | 0x9A + array | *size*: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9B + object | *size*: 0..23 | map | 0xA0..0xB7 + object | *size*: 23..255 | map (1 byte follow) | 0xB8 + object | *size*: 256..65535 | map (2 bytes follow) | 0xB9 + object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xBA + object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xBB + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a CBOR value. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @note The following CBOR types are not used in the conversion: + - byte strings (0x40..0x5F) + - UTF-8 strings terminated by "break" (0x7F) + - arrays terminated by "break" (0x9F) + - maps terminated by "break" (0xBF) + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - tagged items (0xC6..0xD4, 0xD8..0xDB) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) + - half and single-precision floats (0xF9-0xFA) + - break (0xFF) + + @param[in] j JSON value to serialize + @return MessagePack serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in CBOR format.,to_cbor} + + @sa http://cbor.io + @sa @ref from_cbor(detail::input_adapter, const bool strict) for the + analogous deserialization + @sa @ref to_msgpack(const basic_json&) for the related MessagePack format + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + related UBJSON format + + @since version 2.0.9 + */ +static std::vector to_cbor(const basic_json& j) +{ +std::vector result; +to_cbor(j, result); +return result; +} + +static void to_cbor(const basic_json& j, detail::output_adapter o) +{ +binary_writer(o).write_cbor(j); +} + +static void to_cbor(const basic_json& j, detail::output_adapter o) +{ +binary_writer(o).write_cbor(j); +} + +/*! + @brief create a MessagePack serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the MessagePack + serialization format. MessagePack is a binary serialization format which + aims to be more compact than JSON itself, yet more efficient to parse. + + The library uses the following mapping from JSON values types to + MessagePack types according to the MessagePack specification: + + JSON value type | value/range | MessagePack type | first byte + --------------- | --------------------------------- | ---------------- | ---------- + null | `null` | nil | 0xC0 + boolean | `true` | true | 0xC3 + boolean | `false` | false | 0xC2 + number_integer | -9223372036854775808..-2147483649 | int64 | 0xD3 + number_integer | -2147483648..-32769 | int32 | 0xD2 + number_integer | -32768..-129 | int16 | 0xD1 + number_integer | -128..-33 | int8 | 0xD0 + number_integer | -32..-1 | negative fixint | 0xE0..0xFF + number_integer | 0..127 | positive fixint | 0x00..0x7F + number_integer | 128..255 | uint 8 | 0xCC + number_integer | 256..65535 | uint 16 | 0xCD + number_integer | 65536..4294967295 | uint 32 | 0xCE + number_integer | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_unsigned | 0..127 | positive fixint | 0x00..0x7F + number_unsigned | 128..255 | uint 8 | 0xCC + number_unsigned | 256..65535 | uint 16 | 0xCD + number_unsigned | 65536..4294967295 | uint 32 | 0xCE + number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_float | *any value* | float 64 | 0xCB + string | *length*: 0..31 | fixstr | 0xA0..0xBF + string | *length*: 32..255 | str 8 | 0xD9 + string | *length*: 256..65535 | str 16 | 0xDA + string | *length*: 65536..4294967295 | str 32 | 0xDB + array | *size*: 0..15 | fixarray | 0x90..0x9F + array | *size*: 16..65535 | array 16 | 0xDC + array | *size*: 65536..4294967295 | array 32 | 0xDD + object | *size*: 0..15 | fix map | 0x80..0x8F + object | *size*: 16..65535 | map 16 | 0xDE + object | *size*: 65536..4294967295 | map 32 | 0xDF + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a MessagePack value. + + @note The following values can **not** be converted to a MessagePack value: + - strings with more than 4294967295 bytes + - arrays with more than 4294967295 elements + - objects with more than 4294967295 elements + + @note The following MessagePack types are not used in the conversion: + - bin 8 - bin 32 (0xC4..0xC6) + - ext 8 - ext 32 (0xC7..0xC9) + - float 32 (0xCA) + - fixext 1 - fixext 16 (0xD4..0xD8) + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @param[in] j JSON value to serialize + @return MessagePack serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in MessagePack format.,to_msgpack} + + @sa http://msgpack.org + @sa @ref from_msgpack(const std::vector&, const size_t) for the + analogous deserialization + @sa @ref to_cbor(const basic_json& for the related CBOR format + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + related UBJSON format + + @since version 2.0.9 + */ +static std::vector to_msgpack(const basic_json& j) +{ +std::vector result; +to_msgpack(j, result); +return result; +} + +static void to_msgpack(const basic_json& j, detail::output_adapter o) +{ +binary_writer(o).write_msgpack(j); +} + +static void to_msgpack(const basic_json& j, detail::output_adapter o) +{ +binary_writer(o).write_msgpack(j); +} + +/*! + @brief create a UBJSON serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the UBJSON + (Universal Binary JSON) serialization format. UBJSON aims to be more compact + than JSON itself, yet more efficient to parse. + + The library uses the following mapping from JSON values types to + UBJSON types according to the UBJSON specification: + + JSON value type | value/range | UBJSON type | marker + --------------- | --------------------------------- | ----------- | ------ + null | `null` | null | `Z` + boolean | `true` | true | `T` + boolean | `false` | false | `F` + number_integer | -9223372036854775808..-2147483649 | int64 | `L` + number_integer | -2147483648..-32769 | int32 | `l` + number_integer | -32768..-129 | int16 | `I` + number_integer | -128..127 | int8 | `i` + number_integer | 128..255 | uint8 | `U` + number_integer | 256..32767 | int16 | `I` + number_integer | 32768..2147483647 | int32 | `l` + number_integer | 2147483648..9223372036854775807 | int64 | `L` + number_unsigned | 0..127 | int8 | `i` + number_unsigned | 128..255 | uint8 | `U` + number_unsigned | 256..32767 | int16 | `I` + number_unsigned | 32768..2147483647 | int32 | `l` + number_unsigned | 2147483648..9223372036854775807 | int64 | `L` + number_float | *any value* | float64 | `D` + string | *with shortest length indicator* | string | `S` + array | *see notes on optimized format* | array | `[` + object | *see notes on optimized format* | map | `{` + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a UBJSON value. + + @note The following values can **not** be converted to a UBJSON value: + - strings with more than 9223372036854775807 bytes (theoretical) + - unsigned integer numbers above 9223372036854775807 + + @note The following markers are not used in the conversion: + - `Z`: no-op values are not created. + - `C`: single-byte strings are serialized with `S` markers. + + @note Any UBJSON output created @ref to_ubjson can be successfully parsed + by @ref from_ubjson. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @note The optimized formats for containers are supported: Parameter + @a use_size adds size information to the beginning of a container and + removes the closing marker. Parameter @a use_type further checks + whether all elements of a container have the same type and adds the + type marker to the beginning of the container. The @a use_type + parameter must only be used together with @a use_size = true. Note + that @a use_size = true alone may result in larger representations - + the benefit of this parameter is that the receiving side is + immediately informed on the number of elements of the container. + + @param[in] j JSON value to serialize + @param[in] use_size whether to add size annotations to container types + @param[in] use_type whether to add type annotations to container types + (must be combined with @a use_size = true) + @return UBJSON serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in UBJSON format.,to_ubjson} + + @sa http://ubjson.org + @sa @ref from_ubjson(detail::input_adapter, const bool strict) for the + analogous deserialization + @sa @ref to_cbor(const basic_json& for the related CBOR format + @sa @ref to_msgpack(const basic_json&) for the related MessagePack format + + @since version 3.1.0 + */ +static std::vector to_ubjson(const basic_json& j, +const bool use_size = false, +const bool use_type = false) +{ +std::vector result; +to_ubjson(j, result, use_size, use_type); +return result; +} + +static void to_ubjson(const basic_json& j, detail::output_adapter o, +const bool use_size = false, const bool use_type = false) +{ +binary_writer(o).write_ubjson(j, use_size, use_type); +} + +static void to_ubjson(const basic_json& j, detail::output_adapter o, +const bool use_size = false, const bool use_type = false) +{ +binary_writer(o).write_ubjson(j, use_size, use_type); +} + +/*! + @brief create a JSON value from an input in CBOR format + + Deserializes a given input @a i to a JSON value using the CBOR (Concise + Binary Object Representation) serialization format. + + The library maps CBOR types to JSON value types as follows: + + CBOR type | JSON value type | first byte + ---------------------- | --------------- | ---------- + Integer | number_unsigned | 0x00..0x17 + Unsigned integer | number_unsigned | 0x18 + Unsigned integer | number_unsigned | 0x19 + Unsigned integer | number_unsigned | 0x1A + Unsigned integer | number_unsigned | 0x1B + Negative integer | number_integer | 0x20..0x37 + Negative integer | number_integer | 0x38 + Negative integer | number_integer | 0x39 + Negative integer | number_integer | 0x3A + Negative integer | number_integer | 0x3B + Negative integer | number_integer | 0x40..0x57 + UTF-8 string | string | 0x60..0x77 + UTF-8 string | string | 0x78 + UTF-8 string | string | 0x79 + UTF-8 string | string | 0x7A + UTF-8 string | string | 0x7B + UTF-8 string | string | 0x7F + array | array | 0x80..0x97 + array | array | 0x98 + array | array | 0x99 + array | array | 0x9A + array | array | 0x9B + array | array | 0x9F + map | object | 0xA0..0xB7 + map | object | 0xB8 + map | object | 0xB9 + map | object | 0xBA + map | object | 0xBB + map | object | 0xBF + False | `false` | 0xF4 + True | `true` | 0xF5 + Nill | `null` | 0xF6 + Half-Precision Float | number_float | 0xF9 + Single-Precision Float | number_float | 0xFA + Double-Precision Float | number_float | 0xFB + + @warning The mapping is **incomplete** in the sense that not all CBOR + types can be converted to a JSON value. The following CBOR types + are not supported and will yield parse errors (parse_error.112): + - byte strings (0x40..0x5F) + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - tagged items (0xC6..0xD4, 0xD8..0xDB) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) + + @warning CBOR allows map keys of any type, whereas JSON only allows + strings as keys in object values. Therefore, CBOR maps with keys + other than UTF-8 strings are rejected (parse_error.113). + + @note Any CBOR output created @ref to_cbor can be successfully parsed by + @ref from_cbor. + + @param[in] i an input in CBOR format convertible to an input adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + @return deserialized JSON value + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if unsupported features from CBOR were + used in the given input @a v or if the input is not valid CBOR + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in CBOR + format to a JSON value.,from_cbor} + + @sa http://cbor.io + @sa @ref to_cbor(const basic_json&) for the analogous serialization + @sa @ref from_msgpack(detail::input_adapter, const bool) for the + related MessagePack format + @sa @ref from_ubjson(detail::input_adapter, const bool) for the related + UBJSON format + + @since version 2.0.9; parameter @a start_index since 2.1.1; changed to + consume input adapters, removed start_index parameter, and added + @a strict parameter since 3.0.0 + */ +static basic_json from_cbor(detail::input_adapter i, +const bool strict = true) +{ +return binary_reader(i).parse_cbor(strict); +} + +/*! + @copydoc from_cbor(detail::input_adapter, const bool) + */ +template::value, int> = 0> +static basic_json from_cbor(A1 && a1, A2 && a2, const bool strict = true) +{ +return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_cbor(strict); +} + +/*! + @brief create a JSON value from an input in MessagePack format + + Deserializes a given input @a i to a JSON value using the MessagePack + serialization format. + + The library maps MessagePack types to JSON value types as follows: + + MessagePack type | JSON value type | first byte + ---------------- | --------------- | ---------- + positive fixint | number_unsigned | 0x00..0x7F + fixmap | object | 0x80..0x8F + fixarray | array | 0x90..0x9F + fixstr | string | 0xA0..0xBF + nil | `null` | 0xC0 + false | `false` | 0xC2 + true | `true` | 0xC3 + float 32 | number_float | 0xCA + float 64 | number_float | 0xCB + uint 8 | number_unsigned | 0xCC + uint 16 | number_unsigned | 0xCD + uint 32 | number_unsigned | 0xCE + uint 64 | number_unsigned | 0xCF + int 8 | number_integer | 0xD0 + int 16 | number_integer | 0xD1 + int 32 | number_integer | 0xD2 + int 64 | number_integer | 0xD3 + str 8 | string | 0xD9 + str 16 | string | 0xDA + str 32 | string | 0xDB + array 16 | array | 0xDC + array 32 | array | 0xDD + map 16 | object | 0xDE + map 32 | object | 0xDF + negative fixint | number_integer | 0xE0-0xFF + + @warning The mapping is **incomplete** in the sense that not all + MessagePack types can be converted to a JSON value. The following + MessagePack types are not supported and will yield parse errors: + - bin 8 - bin 32 (0xC4..0xC6) + - ext 8 - ext 32 (0xC7..0xC9) + - fixext 1 - fixext 16 (0xD4..0xD8) + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @param[in] i an input in MessagePack format convertible to an input + adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if unsupported features from MessagePack were + used in the given input @a i or if the input is not valid MessagePack + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in + MessagePack format to a JSON value.,from_msgpack} + + @sa http://msgpack.org + @sa @ref to_msgpack(const basic_json&) for the analogous serialization + @sa @ref from_cbor(detail::input_adapter, const bool) for the related CBOR + format + @sa @ref from_ubjson(detail::input_adapter, const bool) for the related + UBJSON format + + @since version 2.0.9; parameter @a start_index since 2.1.1; changed to + consume input adapters, removed start_index parameter, and added + @a strict parameter since 3.0.0 + */ +static basic_json from_msgpack(detail::input_adapter i, +const bool strict = true) +{ +return binary_reader(i).parse_msgpack(strict); +} + +/*! + @copydoc from_msgpack(detail::input_adapter, const bool) + */ +template::value, int> = 0> +static basic_json from_msgpack(A1 && a1, A2 && a2, const bool strict = true) +{ +return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_msgpack(strict); +} + +/*! + @brief create a JSON value from an input in UBJSON format + + Deserializes a given input @a i to a JSON value using the UBJSON (Universal + Binary JSON) serialization format. + + The library maps UBJSON types to JSON value types as follows: + + UBJSON type | JSON value type | marker + ----------- | --------------------------------------- | ------ + no-op | *no value, next value is read* | `N` + null | `null` | `Z` + false | `false` | `F` + true | `true` | `T` + float32 | number_float | `d` + float64 | number_float | `D` + uint8 | number_unsigned | `U` + int8 | number_integer | `i` + int16 | number_integer | `I` + int32 | number_integer | `l` + int64 | number_integer | `L` + string | string | `S` + char | string | `C` + array | array (optimized values are supported) | `[` + object | object (optimized values are supported) | `{` + + @note The mapping is **complete** in the sense that any UBJSON value can + be converted to a JSON value. + + @param[in] i an input in UBJSON format convertible to an input adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if a parse error occurs + @throw parse_error.113 if a string could not be parsed successfully + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in + UBJSON format to a JSON value.,from_ubjson} + + @sa http://ubjson.org + @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the + analogous serialization + @sa @ref from_cbor(detail::input_adapter, const bool) for the related CBOR + format + @sa @ref from_msgpack(detail::input_adapter, const bool) for the related + MessagePack format + + @since version 3.1.0 + */ +static basic_json from_ubjson(detail::input_adapter i, +const bool strict = true) +{ +return binary_reader(i).parse_ubjson(strict); +} + +template::value, int> = 0> +static basic_json from_ubjson(A1 && a1, A2 && a2, const bool strict = true) +{ +return binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).parse_ubjson(strict); +} + +/// @} + +////////////////////////// +// JSON Pointer support // +////////////////////////// + +/// @name JSON Pointer functions +/// @{ + +/*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. Similar to @ref operator[](const typename + object_t::key_type&), `null` values are created in arrays and objects if + necessary. + + In particular: + - If the JSON pointer points to an object key that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. + - If the JSON pointer points to an array index that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. All indices between the current maximum and the given + index are also filled with `null`. + - The special value `-` is treated as a synonym for the index past the + end. + + @param[in] ptr a JSON pointer + + @return reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + + @liveexample{The behavior is shown in the example.,operatorjson_pointer} + + @since version 2.0.0 + */ +reference operator[](const json_pointer& ptr) +{ +return ptr.get_unchecked(this); +} + +/*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. The function does not change the JSON + value; no `null` values are created. In particular, the the special value + `-` yields an exception. + + @param[in] ptr JSON pointer to the desired element + + @return const reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + + @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} + + @since version 2.0.0 + */ +const_reference operator[](const json_pointer& ptr) const +{ +return ptr.get_unchecked(this); +} + +/*! + @brief access specified element via JSON Pointer + + Returns a reference to the element at with specified JSON pointer @a ptr, + with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. + + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. + + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer} + */ +reference at(const json_pointer& ptr) +{ +return ptr.get_checked(this); +} + +/*! + @brief access specified element via JSON Pointer + + Returns a const reference to the element at with specified JSON pointer @a + ptr, with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. + + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. + + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer_const} + */ +const_reference at(const json_pointer& ptr) const +{ +return ptr.get_checked(this); +} + +/*! + @brief return flattened JSON value + + The function creates a JSON object whose keys are JSON pointers (see [RFC + 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all + primitive. The original JSON value can be restored using the @ref + unflatten() function. + + @return an object that maps JSON pointers to primitive values + + @note Empty objects and arrays are flattened to `null` and will not be + reconstructed correctly by the @ref unflatten() function. + + @complexity Linear in the size the JSON value. + + @liveexample{The following code shows how a JSON object is flattened to an + object whose keys consist of JSON pointers.,flatten} + + @sa @ref unflatten() for the reverse function + + @since version 2.0.0 + */ +basic_json flatten() const +{ +basic_json result(value_t::object); +json_pointer::flatten("", *this, result); +return result; +} + +/*! + @brief unflatten a previously flattened JSON value + + The function restores the arbitrary nesting of a JSON value that has been + flattened before using the @ref flatten() function. The JSON value must + meet certain constraints: + 1. The value must be an object. + 2. The keys must be JSON pointers (see + [RFC 6901](https://tools.ietf.org/html/rfc6901)) + 3. The mapped values must be primitive JSON types. + + @return the original JSON from a flattened version + + @note Empty objects and arrays are flattened by @ref flatten() to `null` + values and can not unflattened to their original type. Apart from + this example, for a JSON value `j`, the following is always true: + `j == j.flatten().unflatten()`. + + @complexity Linear in the size the JSON value. + + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + + @liveexample{The following code shows how a flattened JSON object is + unflattened into the original nested JSON object.,unflatten} + + @sa @ref flatten() for the reverse function + + @since version 2.0.0 + */ +basic_json unflatten() const +{ +return json_pointer::unflatten(*this); +} + +/// @} + +////////////////////////// +// JSON Patch functions // +////////////////////////// + +/// @name JSON Patch functions +/// @{ + +/*! + @brief applies a JSON patch + + [JSON Patch](http://jsonpatch.com) defines a JSON document structure for + expressing a sequence of operations to apply to a JSON) document. With + this function, a JSON Patch is applied to the current JSON value by + executing all operations from the patch. + + @param[in] json_patch JSON patch document + @return patched document + + @note The application of a patch is atomic: Either all operations succeed + and the patched document is returned or an exception is thrown. In + any case, the original value is not changed: the patch is applied + to a copy of the value. + + @throw parse_error.104 if the JSON patch does not consist of an array of + objects + + @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory + attributes are missing); example: `"operation add must have member path"` + + @throw out_of_range.401 if an array index is out of range. + + @throw out_of_range.403 if a JSON pointer inside the patch could not be + resolved successfully in the current JSON value; example: `"key baz not + found"` + + @throw out_of_range.405 if JSON pointer has no parent ("add", "remove", + "move") + + @throw other_error.501 if "test" operation was unsuccessful + + @complexity Linear in the size of the JSON value and the length of the + JSON patch. As usually only a fraction of the JSON value is affected by + the patch, the complexity can usually be neglected. + + @liveexample{The following code shows how a JSON patch is applied to a + value.,patch} + + @sa @ref diff -- create a JSON patch by comparing two JSON values + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) + + @since version 2.0.0 + */ +basic_json patch(const basic_json& json_patch) const +{ +// make a working copy to apply the patch to +basic_json result = *this; + +// the valid JSON Patch operations +enum class patch_operations {add, remove, replace, move, copy, test, invalid}; + +const auto get_op = [](const std::string & op) +{ +if (op == "add") +{ +return patch_operations::add; +} +if (op == "remove") +{ +return patch_operations::remove; +} +if (op == "replace") +{ +return patch_operations::replace; +} +if (op == "move") +{ +return patch_operations::move; +} +if (op == "copy") +{ +return patch_operations::copy; +} +if (op == "test") +{ +return patch_operations::test; +} + +return patch_operations::invalid; +}; + +// wrapper for "add" operation; add value at ptr +const auto operation_add = [&result](json_pointer & ptr, basic_json val) +{ +// adding to the root of the target document means replacing it +if (ptr.is_root()) +{ +result = val; +} +else +{ +// make sure the top element of the pointer exists +json_pointer top_pointer = ptr.top(); +if (top_pointer != ptr) +{ +result.at(top_pointer); +} + +// get reference to parent of JSON pointer ptr +const auto last_path = ptr.pop_back(); +basic_json& parent = result[ptr]; + +switch (parent.m_type) +{ +case value_t::null: +case value_t::object: +{ +// use operator[] to add value +parent[last_path] = val; +break; +} + +case value_t::array: +{ +if (last_path == "-") +{ +// special case: append to back +parent.push_back(val); +} +else +{ +const auto idx = json_pointer::array_index(last_path); +if (JSON_UNLIKELY(static_cast(idx) > parent.size())) +{ +// avoid undefined behavior +JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); +} +else +{ +// default case: insert add offset +parent.insert(parent.begin() + static_cast(idx), val); +} +} +break; +} + +default: +{ +// if there exists a parent it cannot be primitive +assert(false); // LCOV_EXCL_LINE +} +} +} +}; + +// wrapper for "remove" operation; remove value at ptr +const auto operation_remove = [&result](json_pointer & ptr) +{ +// get reference to parent of JSON pointer ptr +const auto last_path = ptr.pop_back(); +basic_json& parent = result.at(ptr); + +// remove child +if (parent.is_object()) +{ +// perform range check +auto it = parent.find(last_path); +if (JSON_LIKELY(it != parent.end())) +{ +parent.erase(it); +} +else +{ +JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found")); +} +} +else if (parent.is_array()) +{ +// note erase performs range check +parent.erase(static_cast(json_pointer::array_index(last_path))); +} +}; + +// type check: top level value must be an array +if (JSON_UNLIKELY(not json_patch.is_array())) +{ +JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); +} + +// iterate and apply the operations +for (const auto& val : json_patch) +{ +// wrapper to get a value for an operation +const auto get_value = [&val](const std::string & op, +const std::string & member, +bool string_type) -> basic_json & +{ +// find value +auto it = val.m_value.object->find(member); + +// context-sensitive error message +const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; + +// check if desired value is present +if (JSON_UNLIKELY(it == val.m_value.object->end())) +{ +JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'")); +} + +// check if result is of type string +if (JSON_UNLIKELY(string_type and not it->second.is_string())) +{ +JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'")); +} + +// no error: return value +return it->second; +}; + +// type check: every element of the array must be an object +if (JSON_UNLIKELY(not val.is_object())) +{ +JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); +} + +// collect mandatory members +const std::string op = get_value("op", "op", true); +const std::string path = get_value(op, "path", true); +json_pointer ptr(path); + +switch (get_op(op)) +{ +case patch_operations::add: +{ +operation_add(ptr, get_value("add", "value", false)); +break; +} + +case patch_operations::remove: +{ +operation_remove(ptr); +break; +} + +case patch_operations::replace: +{ +// the "path" location must exist - use at() +result.at(ptr) = get_value("replace", "value", false); +break; +} + +case patch_operations::move: +{ +const std::string from_path = get_value("move", "from", true); +json_pointer from_ptr(from_path); + +// the "from" location must exist - use at() +basic_json v = result.at(from_ptr); + +// The move operation is functionally identical to a +// "remove" operation on the "from" location, followed +// immediately by an "add" operation at the target +// location with the value that was just removed. +operation_remove(from_ptr); +operation_add(ptr, v); +break; +} + +case patch_operations::copy: +{ +const std::string from_path = get_value("copy", "from", true); +const json_pointer from_ptr(from_path); + +// the "from" location must exist - use at() +basic_json v = result.at(from_ptr); + +// The copy is functionally identical to an "add" +// operation at the target location using the value +// specified in the "from" member. +operation_add(ptr, v); +break; +} + +case patch_operations::test: +{ +bool success = false; +JSON_TRY +{ +// check if "value" matches the one at "path" +// the "path" location must exist - use at() +success = (result.at(ptr) == get_value("test", "value", false)); +} +JSON_CATCH (out_of_range&) +{ +// ignore out of range errors: success remains false +} + +// throw an exception if test fails +if (JSON_UNLIKELY(not success)) +{ +JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump())); +} + +break; +} + +case patch_operations::invalid: +{ +// op must be "add", "remove", "replace", "move", "copy", or +// "test" +JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid")); +} +} +} + +return result; +} + +/*! + @brief creates a diff as a JSON patch + + Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can + be changed into the value @a target by calling @ref patch function. + + @invariant For two JSON values @a source and @a target, the following code + yields always `true`: + @code {.cpp} + source.patch(diff(source, target)) == target; + @endcode + + @note Currently, only `remove`, `add`, and `replace` operations are + generated. + + @param[in] source JSON value to compare from + @param[in] target JSON value to compare against + @param[in] path helper value to create JSON pointers + + @return a JSON patch to convert the @a source to @a target + + @complexity Linear in the lengths of @a source and @a target. + + @liveexample{The following code shows how a JSON patch is created as a + diff for two JSON values.,diff} + + @sa @ref patch -- apply a JSON patch + @sa @ref merge_patch -- apply a JSON Merge Patch + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + + @since version 2.0.0 + */ +static basic_json diff(const basic_json& source, const basic_json& target, +const std::string& path = "") +{ +// the patch +basic_json result(value_t::array); + +// if the values are the same, return empty patch +if (source == target) +{ +return result; +} + +if (source.type() != target.type()) +{ +// different types: replace value +result.push_back( +{ +{"op", "replace"}, {"path", path}, {"value", target} +}); +} +else +{ +switch (source.type()) +{ +case value_t::array: +{ +// first pass: traverse common elements +std::size_t i = 0; +while (i < source.size() and i < target.size()) +{ +// recursive call to compare array values at index i +auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); +result.insert(result.end(), temp_diff.begin(), temp_diff.end()); +++i; +} + +// i now reached the end of at least one array +// in a second pass, traverse the remaining elements + +// remove my remaining elements +const auto end_index = static_cast(result.size()); +while (i < source.size()) +{ +// add operations in reverse order to avoid invalid +// indices +result.insert(result.begin() + end_index, object( +{ +{"op", "remove"}, +{"path", path + "/" + std::to_string(i)} +})); +++i; +} + +// add other remaining elements +while (i < target.size()) +{ +result.push_back( +{ +{"op", "add"}, +{"path", path + "/" + std::to_string(i)}, +{"value", target[i]} +}); +++i; +} + +break; +} + +case value_t::object: +{ +// first pass: traverse this object's elements +for (auto it = source.cbegin(); it != source.cend(); ++it) +{ +// escape the key name to be used in a JSON patch +const auto key = json_pointer::escape(it.key()); + +if (target.find(it.key()) != target.end()) +{ +// recursive call to compare object values at key it +auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); +result.insert(result.end(), temp_diff.begin(), temp_diff.end()); +} +else +{ +// found a key that is not in o -> remove it +result.push_back(object( +{ +{"op", "remove"}, {"path", path + "/" + key} +})); +} +} + +// second pass: traverse other object's elements +for (auto it = target.cbegin(); it != target.cend(); ++it) +{ +if (source.find(it.key()) == source.end()) +{ +// found a key that is not in this -> add it +const auto key = json_pointer::escape(it.key()); +result.push_back( +{ +{"op", "add"}, {"path", path + "/" + key}, +{"value", it.value()} +}); +} +} + +break; +} + +default: +{ +// both primitive type: replace value +result.push_back( +{ +{"op", "replace"}, {"path", path}, {"value", target} +}); +break; +} +} +} + +return result; +} + +/// @} + +//////////////////////////////// +// JSON Merge Patch functions // +//////////////////////////////// + +/// @name JSON Merge Patch functions +/// @{ + +/*! + @brief applies a JSON Merge Patch + + The merge patch format is primarily intended for use with the HTTP PATCH + method as a means of describing a set of modifications to a target + resource's content. This function applies a merge patch to the current + JSON value. + + The function implements the following algorithm from Section 2 of + [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396): + + ``` + define MergePatch(Target, Patch): + if Patch is an Object: + if Target is not an Object: + Target = {} // Ignore the contents and set it to an empty Object + for each Name/Value pair in Patch: + if Value is null: + if Name exists in Target: + remove the Name/Value pair from Target + else: + Target[Name] = MergePatch(Target[Name], Value) + return Target + else: + return Patch + ``` + + Thereby, `Target` is the current object; that is, the patch is applied to + the current value. + + @param[in] patch the patch to apply + + @complexity Linear in the lengths of @a patch. + + @liveexample{The following code shows how a JSON Merge Patch is applied to + a JSON document.,merge_patch} + + @sa @ref patch -- apply a JSON patch + @sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396) + + @since version 3.0.0 + */ +void merge_patch(const basic_json& patch) +{ +if (patch.is_object()) +{ +if (not is_object()) +{ +*this = object(); +} +for (auto it = patch.begin(); it != patch.end(); ++it) +{ +if (it.value().is_null()) +{ +erase(it.key()); +} +else +{ +operator[](it.key()).merge_patch(it.value()); +} +} +} +else +{ +*this = patch; +} +} + +/// @} +}; +} // namespace nlohmann + +/////////////////////// +// nonmember support // +/////////////////////// + +// specialization of std::swap, and std::hash +namespace std +{ +/*! +@brief exchanges the values of two JSON objects + +@since version 1.0.0 +*/ +template<> +inline void swap(nlohmann::json& j1, +nlohmann::json& j2) noexcept( +is_nothrow_move_constructible::value and +is_nothrow_move_assignable::value +) +{ +j1.swap(j2); +} + +/// hash value for JSON objects +template<> +struct hash +{ +/*! + @brief return a hash value for a JSON object + + @since version 1.0.0 + */ +std::size_t operator()(const nlohmann::json& j) const +{ +// a naive hashing via the string representation +const auto& h = hash(); +return h(j.dump()); +} +}; + +/// specialization for std::less +/// @note: do not remove the space after '<', +/// see https://github.com/nlohmann/json/pull/679 +template<> +struct less< ::nlohmann::detail::value_t> +{ +/*! + @brief compare two value_t enum values + @since version 3.0.0 + */ +bool operator()(nlohmann::detail::value_t lhs, +nlohmann::detail::value_t rhs) const noexcept +{ +return nlohmann::detail::operator<(lhs, rhs); +} +}; + +} // namespace std + +/*! +@brief user-defined string literal for JSON values + +This operator implements a user-defined string literal for JSON objects. It +can be used by adding `"_json"` to a string literal and returns a JSON object +if no parse error occurred. + +@param[in] s a string representation of a JSON object +@param[in] n the length of string @a s +@return a JSON object + +@since version 1.0.0 +*/ +inline nlohmann::json operator "" _json(const char* s, std::size_t n) +{ +return nlohmann::json::parse(s, s + n); +} + +/*! +@brief user-defined string literal for JSON pointer + +This operator implements a user-defined string literal for JSON Pointers. It +can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer +object if no parse error occurred. + +@param[in] s a string representation of a JSON Pointer +@param[in] n the length of string @a s +@return a JSON pointer object + +@since version 2.0.0 +*/ +inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) +{ +return nlohmann::json::json_pointer(std::string(s, n)); +} + +// #include + + +// restore GCC/clang diagnostic settings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) +#pragma GCC diagnostic pop +#endif +#if defined(__clang__) +#pragma GCC diagnostic pop +#endif + +// clean up +#undef JSON_CATCH +#undef JSON_THROW +#undef JSON_TRY +#undef JSON_LIKELY +#undef JSON_UNLIKELY +#undef JSON_DEPRECATED +#undef JSON_HAS_CPP_14 +#undef JSON_HAS_CPP_17 +#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION +#undef NLOHMANN_BASIC_JSON_TPL +#undef NLOHMANN_JSON_HAS_HELPER + + +#endif \ No newline at end of file diff --git a/splinter/include/json_parser.h b/splinter/include/json_parser.h new file mode 100644 index 0000000000..363583374b --- /dev/null +++ b/splinter/include/json_parser.h @@ -0,0 +1,29 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#ifndef SPLINTER_JSON_PARSER_H +#define SPLINTER_JSON_PARSER_H + +#include + +namespace SPLINTER +{ + +class BSpline; +class DataTable; + +void bspline_to_json(const BSpline &bspline, const std::string &filename); +BSpline bspline_from_json(const std::string &filename); + +void datatable_to_json(const DataTable &data, const std::string &filename); +DataTable datatable_from_json(const std::string &filename); + +} // namespace SPLINTER + +#endif //SPLINTER_JSON_PARSER_H diff --git a/splinter/include/knot_builders.h b/splinter/include/knot_builders.h new file mode 100644 index 0000000000..0f0738db3b --- /dev/null +++ b/splinter/include/knot_builders.h @@ -0,0 +1,97 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#ifndef SPLINTER_KNOT_UTILS_H +#define SPLINTER_KNOT_UTILS_H + +#include +#include + +namespace SPLINTER +{ + +/** + * B-spline knot spacing + */ +enum class KnotSpacing { + /* + * Experimental knot spacing for testing purposes only. + * Currently, it computes equidistant knots on an expanded interval. + * NOTE: may change in the future + */ + EXPERIMENTAL, + + /* + * Clamped and with knots that mimic the spacing of sample points using a moving average filter. + * Resulting knot vectors have p+1 multiplicity of end knots. This is the default knot spacing for B-spline + * interpolation and smoothing. + * Example for samples at 0, 1, ..., 5: + * Then, for degree 3 the knot vector becomes: [0, 0, 0, 0, 2, 3, 5, 5, 5, 5] + * and for degree 1 the knot vector becomes: [0, 0, 1, 2, 3, 4, 5, 5] + */ + AS_SAMPLED, + + /* + * Clamped knot vector with equidistant internal knots. p+1 multiplicity of end knots. + * Example for samples at 0, 1, ..., 5: + * For degree 3: [0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5] + * For degree 1: [0, 0, 1, 2, 3, 4, 5, 5] + */ + EQUIDISTANT_CLAMPED, + + /* + * Simple knot vector with equidistant knots. Single multiplicity of end knots. Does not vary with degree. + * Example for samples at 0, 1, ..., 5: + * For degree 3: [0, 1, 2, 3, 4, 5] + * For degree 1: [0, 1, 2, 3, 4, 5] + */ + EQUIDISTANT +}; + +/** + * Computing knot vectors + */ +std::vector> build_knot_vectors(const DataTable &data, const std::vector °rees); + +std::vector> build_knot_vectors(const DataTable &data, const std::vector °rees, + KnotSpacing knot_spacing, + const std::vector &num_basis_functions); + +/** + * Computing single knot vector + */ +std::vector build_knot_vector(const std::vector &values, unsigned int degree, + unsigned int num_basis_functions, KnotSpacing knot_spacing); + +/** + * Construct knot vector using moving average filter (AS_SAMPLED) + */ +std::vector knot_vector_moving_average(const std::vector &values, unsigned int degree); + +/** + * Compute clamped, equidistant knot vector (EQUIDISTANT_CLAMPED) + */ +std::vector knot_vector_equidistant_clamped(const std::vector &values, unsigned int degree, + unsigned int num_basis_functions = 0); + +/** + * Construct equidistant knot vector (EQUIDISTANT) + */ +std::vector knot_vector_equidistant(const std::vector &values, unsigned int degree, + unsigned int num_basis_functions); + +/** + * Construct expanded equidistant knot vector (EXPERIMENTAL) + */ +std::vector knot_vector_expanded_equidistant(const std::vector &values, unsigned int degree, + unsigned int num_basis_functions); + +} // namespace SPLINTER + +#endif // SPLINTER_KNOT_UTILS_H diff --git a/splinter/include/knot_vector.h b/splinter/include/knot_vector.h new file mode 100644 index 0000000000..22d022cca5 --- /dev/null +++ b/splinter/include/knot_vector.h @@ -0,0 +1,106 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#ifndef SPLINTER_KNOT_VECTOR_H +#define SPLINTER_KNOT_VECTOR_H + +#include +#include +#include "definitions.h" + +namespace SPLINTER +{ + +/** + * Class representing a knot vector (nondecreasing sequence of number) + */ +class KnotVector +{ +public: + KnotVector() + : knots(std::vector()) + { + } + + KnotVector(const std::vector &knots) + : knots(std::vector(knots)) + { + // Test knots here + if (!is_nondecreasing()) + throw Exception("KnotVector::KnotVector: Knot vector is not nondecreasing."); + } + + std::vector get_values() const { + // Return copy of knots + return knots; + } + + bool is_nondecreasing() const { + return std::is_sorted(knots.begin(), knots.end()); + } + + bool is_regular(unsigned int degree) const; + + bool is_clamped(unsigned int degree) const; + + bool is_refinement(const KnotVector &refined_knots) const { + return is_refinement(refined_knots.get_values()); + } + + bool is_refinement(const std::vector &refined_knots) const; + + bool is_supported(double x) const { + return (knots.front() <= x) && (x <= knots.back()); + } + + unsigned int multiplicity(double tau) const { + return (unsigned int)std::count(knots.begin(), knots.end(), tau); + } + + unsigned int index_interval(double x) const; + + std::vector::size_type size() const { + return knots.size(); + } + + bool empty() const { + return knots.empty(); + } + + std::vector::const_iterator cbegin() const { + return knots.cbegin(); + } + + std::vector::const_iterator cend() const { + return knots.cend(); + } + + const double& at(unsigned int i) const { + return knots.at(i); + } + + const double& front() const { + return knots.front(); + } + + const double& back() const { + return knots.back(); + } + +private: + std::vector knots; + +}; + +bool operator==(const KnotVector &lhs, const KnotVector &rhs); +bool operator!=(const KnotVector &lhs, const KnotVector &rhs); + +} // namespace SPLINTER + +#endif // SPLINTER_KNOT_VECTOR_H diff --git a/splinter/mykroneckerproduct.h b/splinter/include/kronecker_product.h similarity index 52% rename from splinter/mykroneckerproduct.h rename to splinter/include/kronecker_product.h index 7e5254df4a..8701004c91 100644 --- a/splinter/mykroneckerproduct.h +++ b/splinter/include/kronecker_product.h @@ -7,21 +7,21 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef SPLINTER_MYKRONECKERPRODUCT_H -#define SPLINTER_MYKRONECKERPRODUCT_H +#ifndef SPLINTER_KRONECKER_PRODUCT_H +#define SPLINTER_KRONECKER_PRODUCT_H #include "definitions.h" namespace SPLINTER { -SparseMatrix myKroneckerProduct(const SparseMatrix &A, const SparseMatrix &B); +SparseMatrix my_kronecker_product(const SparseMatrix &A, const SparseMatrix &B); // Apply Kronecker product on several vectors or matrices -SparseVector kroneckerProductVectors(const std::vector &vectors); -DenseVector kroneckerProductVectors(const std::vector &vectors); -SparseMatrix kroneckerProductMatrices(const std::vector &matrices); +SparseVector kronecker_product_vectors(const std::vector &vectors); +DenseVector kronecker_product_vectors(const std::vector &vectors); +SparseMatrix kronecker_product_matrices(const std::vector &matrices); } // namespace SPLINTER -#endif // SPLINTER_MYKRONECKERPRODUCT_H +#endif // SPLINTER_KRONECKER_PRODUCT_H diff --git a/splinter/linearsolvers.h b/splinter/include/linear_solvers.h similarity index 64% rename from splinter/linearsolvers.h rename to splinter/include/linear_solvers.h index f2b319af9b..5a9f5b2791 100644 --- a/splinter/linearsolvers.h +++ b/splinter/include/linear_solvers.h @@ -7,16 +7,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef SPLINTER_LINEARSOLVER_H -#define SPLINTER_LINEARSOLVER_H +#ifndef SPLINTER_LINEAR_SOLVER_H +#define SPLINTER_LINEAR_SOLVER_H #include "definitions.h" #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push -// fails CentOS 7 #pragma GCC diagnostic ignored "-Wignored-attributes" +#pragma GCC diagnostic ignored "-Wignored-attributes" #endif -#include "IterativeLinearSolvers" -#include "SparseQR" +#include "Eigen/IterativeLinearSolvers" +#include "Eigen/SparseQR" #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif @@ -30,15 +30,15 @@ class LinearSolver public: bool solve(const lhs &A, const rhs &b, rhs &x) const { - if (!consistentData(A, b)) + if (!consistent_data(A, b)) throw Exception("LinearSolver::solve: Inconsistent matrix dimensions!"); - bool success = doSolve(A, b, x); + bool success = do_solve(A, b, x); if (!success) throw Exception("LinearSolver::solve: Solver did not converge to acceptable tolerance!"); -// if (!validSolution(A, b, x)) +// if (!valid_solution(A, b, x)) // throw Exception("LinearSolver::solve: Invalid solution!"); return true; @@ -48,14 +48,14 @@ class LinearSolver private: double tol = 1e-12; // Relative error tolerance - virtual bool doSolve(const lhs &A, const rhs &b, rhs &x) const = 0; + virtual bool do_solve(const lhs &A, const rhs &b, rhs &x) const = 0; - bool consistentData(const lhs &A, const rhs &b) const + bool consistent_data(const lhs &A, const rhs &b) const { return A.rows() == b.rows(); } - bool validSolution(const lhs &A, const rhs &b, const rhs &x) const + bool valid_solution(const lhs &A, const rhs &b, const rhs &x) const { //return b.isApprox(A*x); double err = (A*x - b).norm() / b.norm(); @@ -68,7 +68,7 @@ template class DenseSVD : public LinearSolver { private: - bool doSolve(const DenseMatrix &A, const rhs &b, rhs &x) const + bool do_solve(const DenseMatrix &A, const rhs &b, rhs &x) const { // Solve linear system Eigen::JacobiSVD svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV); @@ -81,7 +81,7 @@ template class DenseQR : public LinearSolver { private: - bool doSolve(const DenseMatrix &A, const rhs &b, rhs &x) const + bool do_solve(const DenseMatrix &A, const rhs &b, rhs &x) const { //x = A.colPivHouseholderQr().solve(b); @@ -103,17 +103,17 @@ template class SparseBiCG : public LinearSolver { private: - bool doSolve(const SparseMatrix &A, const rhs &b, rhs &x) const + bool do_solve(const SparseMatrix &A, const rhs &b, rhs &x) const { // Init BiCGSTAB solver (requires square matrices) - Eigen::BiCGSTAB sparseSolver(A); + Eigen::BiCGSTAB sparse_solver(A); - if (sparseSolver.info() == Eigen::Success) + if (sparse_solver.info() == Eigen::Success) { // Solve LSE - x = sparseSolver.solve(b); + x = sparse_solver.solve(b); - return sparseSolver.info() == Eigen::Success; + return sparse_solver.info() == Eigen::Success; } return false; @@ -124,21 +124,21 @@ template class SparseLU : public LinearSolver { private: - bool doSolve(const SparseMatrix &A, const rhs &b, rhs &x) const + bool do_solve(const SparseMatrix &A, const rhs &b, rhs &x) const { // Init SparseLU solver (requires square matrices) - Eigen::SparseLU sparseSolver; + Eigen::SparseLU sparse_solver; // Compute the ordering permutation vector from the structural pattern of A - sparseSolver.analyzePattern(A); + sparse_solver.analyzePattern(A); // Compute the numerical factorization - sparseSolver.factorize(A); + sparse_solver.factorize(A); - if (sparseSolver.info() == Eigen::Success) + if (sparse_solver.info() == Eigen::Success) { // Solve LSE - x = sparseSolver.solve(b); + x = sparse_solver.solve(b); - return sparseSolver.info() == Eigen::Success; + return sparse_solver.info() == Eigen::Success; } return false; @@ -149,19 +149,19 @@ template class SparseQR : public LinearSolver { private: - bool doSolve(const SparseMatrix &A, const rhs &b, rhs &x) const + bool do_solve(const SparseMatrix &A, const rhs &b, rhs &x) const { // Init SparseQR solver (works with rectangular matrices) - Eigen::SparseQR> sparseSolver; - sparseSolver.analyzePattern(A); - sparseSolver.factorize(A); + Eigen::SparseQR> sparse_solver; + sparse_solver.analyzePattern(A); + sparse_solver.factorize(A); - if (sparseSolver.info() == Eigen::Success) + if (sparse_solver.info() == Eigen::Success) { // Solve LSE - x = sparseSolver.solve(b); + x = sparse_solver.solve(b); - return sparseSolver.info() == Eigen::Success; + return sparse_solver.info() == Eigen::Success; } return false; @@ -170,4 +170,4 @@ class SparseQR : public LinearSolver } // namespace SPLINTER -#endif // SPLINTER_LINEARSOLVER_H +#endif // SPLINTER_LINEAR_SOLVER_H diff --git a/splinter/include/utilities.h b/splinter/include/utilities.h new file mode 100644 index 0000000000..276c702d2f --- /dev/null +++ b/splinter/include/utilities.h @@ -0,0 +1,59 @@ +/* + * This file is part of the SPLINTER library. + * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#ifndef SPLINTER_UTILITIES_H +#define SPLINTER_UTILITIES_H + +#include +#include // For std::abs, etc. +#include + +namespace SPLINTER +{ + +// Compare two numbers +template +bool assert_near(T x, T y, double tolAbs = 1e-8, double tolRel = 1e-8) +{ + double dx = std::abs(x - y); + double xAbs = 0.5*(std::abs(x) + std::abs(y)); + double err = std::max(tolAbs, tolRel*xAbs); + return dx < err; +} + +// Compare two vectors +inline bool compare_vectors(std::vector x, std::vector y, double tolAbs = 1e-8, double tolRel = 1e-8) +{ + if (x.size() != y.size()) + return false; + + for (unsigned int i = 0; i < x.size(); ++i) + if (!assert_near(x.at(i), y.at(i), tolAbs, tolRel)) + return false; + + return true; +} + +std::vector eig_to_std_vec(const DenseVector &vec); + +DenseVector std_to_eig_vec(const std::vector &vec); + +std::vector> eig_to_std_mat(const DenseMatrix &mat); + +DenseMatrix std_to_eig_mat(const std::vector> &vec); + +std::vector linspace(double start, double stop, unsigned int num); + +std::vector extract_unique_sorted(const std::vector &values); + +std::vector> transpose_vec_vec(std::vector> x); + +} // namespace SPLINTER + +#endif // SPLINTER_UTILITIES_H diff --git a/splinter/knots.cpp b/splinter/knots.cpp deleted file mode 100644 index 371c5ca492..0000000000 --- a/splinter/knots.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -#include -#include "knots.h" - -namespace SPLINTER -{ - -bool isKnotVectorRegular(const std::vector &knots, unsigned int degree) -{ - // Check size - if (knots.size() < 2 * (degree + 1)) - return false; - - // Check order - if (!std::is_sorted(knots.begin(), knots.end())) - return false; - - // Check multiplicity of knots - for (std::vector::const_iterator it = knots.begin(); it != knots.end(); ++it) - { - if (count(knots.begin(), knots.end(), *it) > degree + 1) - return false; - } - - return true; -} - -bool isKnotVectorClamped(const std::vector &knots, unsigned int degree) -{ - // Check multiplicity of first knot - if (std::count(knots.begin(), knots.begin() + degree + 1, knots.front()) != degree + 1) - return false; - - // Check multiplicity of last knot - if (std::count(knots.end() - degree - 1, knots.end(), knots.back()) != degree + 1) - return false; - - return true; -} - -bool isKnotVectorRefinement(const std::vector &knots, const std::vector &refinedKnots) -{ - // Check size - if (refinedKnots.size() < knots.size()) - return false; - - // Check that each element in knots occurs at least as many times in refinedKnots - for (std::vector::const_iterator it = knots.begin() ; it != knots.end(); ++it) - { - int m_tau = count(knots.begin(), knots.end(), *it); - int m_t = count(refinedKnots.begin(), refinedKnots.end(), *it); - if (m_t < m_tau) return false; - } - - // Check that range is not changed - if (knots.front() != refinedKnots.front()) return false; - if (knots.back() != refinedKnots.back()) return false; - - return true; -} - -} // namespace SPLINTER diff --git a/splinter/knots.h b/splinter/knots.h deleted file mode 100644 index 399bc54fda..0000000000 --- a/splinter/knots.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -#ifndef SPLINTER_KNOTS_H -#define SPLINTER_KNOTS_H - -#include - -namespace SPLINTER -{ - -// Knot vector related -bool isKnotVectorRegular(const std::vector &knots, unsigned int degree); -bool isKnotVectorClamped(const std::vector &knots, unsigned int degree); -bool isKnotVectorRefinement(const std::vector &knots, const std::vector &refinedKnots); - -} // namespace SPLINTER - -#endif // SPLINTER_KNOTS_H diff --git a/splinter/saveable.h b/splinter/saveable.h deleted file mode 100644 index db2c4a668b..0000000000 --- a/splinter/saveable.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -#ifndef SPLINTER_SAVEABLE_H -#define SPLINTER_SAVEABLE_H - -namespace SPLINTER -{ - -/** - * Interface for save and load functionality - */ -class Saveable -{ -public: - Saveable() {} - virtual ~Saveable() {} - - /** - * Serialize and save object to fileName - * Should throw exception if file could not be opened - */ - virtual void save(const std::string &fileName) const = 0; - -protected: - /** - * Deserialize and load object from fileName - * Should throw exception if file could not be opened - * or if the file format is wrong - */ - virtual void load(const std::string &fileName) = 0; -}; - -} // namespace SPLINTER - -#endif // SPLINTER_SAVEABLE_H diff --git a/splinter/serializer.cpp b/splinter/serializer.cpp deleted file mode 100644 index 1c8ad8a077..0000000000 --- a/splinter/serializer.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -#include "serializer.h" -#include -#include "definitions.h" -#include "datapoint.h" -#include "datatable.h" -#include "bspline.h" -#include "bsplinebasis.h" -#include "bsplinebasis1d.h" - -namespace SPLINTER -{ - -Serializer::Serializer() -{ - stream = StreamType(0); -} - -Serializer::Serializer(const std::string &fileName) -{ - stream = StreamType(0); - loadFromFile(fileName); -} - -void Serializer::saveToFile(const std::string &fileName) -{ - std::fstream fs(fileName, std::fstream::out | std::fstream::binary); - - for (const auto& byte : stream) - fs << byte; -} - -void Serializer::loadFromFile(const std::string &fileName) -{ - // Open the file in binary mode at the end - std::ifstream ifs(fileName, std::ios::binary | std::ios::ate); - - if (!ifs.is_open()) { - std::string error_message("Serializer::loadFromFile: Unable to open file \""); - error_message.append(fileName); - error_message.append("\" for deserializing."); - throw Exception(error_message); - } - - // Because we opened the file at the end, tellg() will give us the size of the file - std::ifstream::pos_type pos = ifs.tellg(); - - std::vector result(pos); - - ifs.seekg(0, std::ios::beg); - - // http://www.cplusplus.com/reference/vector/vector/data/ - // Elements of the vector are guaranteed to be stored in a contiguous array, - // *result.data() can therefore be treated as an array of the same type as the vector - ifs.read(result.data(), pos); - //assert(ifs); - - stream.clear(); - // Convert from char to uint_8 vector - for (const char& byte : result) - stream.push_back((uint8_t)byte); - - read = stream.cbegin(); -} - -/* - * get_size implementations - */ - -size_t Serializer::get_size(const DataPoint &obj) -{ - return get_size(obj.x) + get_size(obj.y); -} - -size_t Serializer::get_size(const DataTable &obj) -{ - return get_size(obj.allowDuplicates) - + get_size(obj.allowIncompleteGrid) - + get_size(obj.numDuplicates) - + get_size(obj.numVariables) - + get_size(obj.samples) - + get_size(obj.grid); -} - -size_t Serializer::get_size(const BSpline &obj) -{ - return get_size(obj.basis) - + get_size(obj.knotaverages) - + get_size(obj.coefficients) - + get_size(obj.numVariables); -} - -size_t Serializer::get_size(const BSplineBasis &obj) -{ - return get_size(obj.bases) - + get_size(obj.numVariables); -} - -size_t Serializer::get_size(const BSplineBasis1D &obj) -{ - return get_size(obj.degree) - + get_size(obj.knots) - + get_size(obj.targetNumBasisfunctions); -} - -size_t Serializer::get_size(const DenseMatrix &obj) -{ - size_t size = sizeof(obj.rows()); - size += sizeof(obj.cols()); - size_t numElements = obj.rows() * obj.cols(); - if (numElements > 0) { - size += numElements * sizeof(obj(0,0)); - } - return size; -} - -size_t Serializer::get_size(const DenseVector &obj) -{ - size_t size = sizeof(obj.rows()); - size_t numElements = obj.rows(); - if (numElements > 0) { - size += numElements * sizeof(obj(0)); - } - return size; -} - -size_t Serializer::get_size(const SparseMatrix &obj) -{ - DenseMatrix temp(obj); - return get_size(temp); -} - -size_t Serializer::get_size(const SparseVector &obj) -{ - DenseVector temp(obj); - return get_size(temp); -} - -/* - * _serialize implementations - */ - -void Serializer::_serialize(const DataPoint &obj) -{ - _serialize(obj.x); - _serialize(obj.y); -} - -void Serializer::_serialize(const DataTable &obj) -{ - _serialize(obj.allowDuplicates); - _serialize(obj.allowIncompleteGrid); - _serialize(obj.numDuplicates); - _serialize(obj.numVariables); - _serialize(obj.samples); - _serialize(obj.grid); -} - -void Serializer::_serialize(const BSpline &obj) -{ - _serialize(obj.basis); - _serialize(obj.knotaverages); - _serialize(obj.coefficients); - _serialize(obj.numVariables); -} - -void Serializer::_serialize(const BSplineBasis &obj) -{ - _serialize(obj.bases); - _serialize(obj.numVariables); -} - -void Serializer::_serialize(const BSplineBasis1D &obj) -{ - _serialize(obj.degree); - _serialize(obj.knots); - _serialize(obj.targetNumBasisfunctions); -} - -void Serializer::_serialize(const DenseMatrix &obj) -{ - // Store the number of matrix rows and columns first - _serialize(obj.rows()); - _serialize(obj.cols()); - // Store the matrix elements - for (size_t i = 0; i < (size_t) obj.rows(); ++i) { - for (size_t j = 0; j < (size_t) obj.cols(); ++j) { - _serialize(obj(i,j)); - } - } -} - -void Serializer::_serialize(const DenseVector &obj) -{ - // Store the number of vector rows - _serialize(obj.rows()); - // Store the vector elements - for (size_t i = 0; i < (size_t) obj.rows(); ++i) { - _serialize(obj(i)); - } -} - -void Serializer::_serialize(const SparseMatrix &obj) -{ - DenseMatrix temp(obj); - _serialize(temp); -} - -void Serializer::_serialize(const SparseVector &obj) -{ - DenseVector temp(obj); - _serialize(temp); -} - -/* - * deserialize implementations - */ - -void Serializer::deserialize(DataPoint &obj) -{ - deserialize(obj.x); - deserialize(obj.y); -} - -void Serializer::deserialize(DataTable &obj) -{ - deserialize(obj.allowDuplicates); - deserialize(obj.allowIncompleteGrid); - deserialize(obj.numDuplicates); - deserialize(obj.numVariables); - deserialize(obj.samples); - deserialize(obj.grid); -} - -void Serializer::deserialize(BSpline &obj) -{ - deserialize(obj.basis); - deserialize(obj.knotaverages); - deserialize(obj.coefficients); - deserialize(obj.numVariables); -} - -void Serializer::deserialize(BSplineBasis &obj) -{ - deserialize(obj.bases); - deserialize(obj.numVariables); -} - -void Serializer::deserialize(BSplineBasis1D &obj) -{ - deserialize(obj.degree); - deserialize(obj.knots); - deserialize(obj.targetNumBasisfunctions); -} - -void Serializer::deserialize(DenseMatrix &obj) -{ - // Retrieve the number of rows - size_t rows; deserialize(rows); - size_t cols; deserialize(cols); - - obj.resize(rows, cols); - - for (size_t i = 0; i < rows; ++i) - { - for (size_t j = 0; j < cols; ++j) - { - deserialize(obj(i, j)); - } - } -} - -void Serializer::deserialize(DenseVector &obj) -{ - // Retrieve the number of rows - size_t rows; deserialize(rows); - - obj.resize(rows); - - for (size_t i = 0; i < rows; ++i) - { - deserialize(obj(i)); - } -} - -void Serializer::deserialize(SparseMatrix &obj) -{ - DenseMatrix temp(obj); - deserialize(temp); - obj = temp.sparseView(); -} - -void Serializer::deserialize(SparseVector &obj) -{ - DenseVector temp(obj); - deserialize(temp); - obj = temp.sparseView(); -} - -} // namespace SPLINTER diff --git a/splinter/serializer.h b/splinter/serializer.h deleted file mode 100644 index 82cb073fc9..0000000000 --- a/splinter/serializer.h +++ /dev/null @@ -1,308 +0,0 @@ -/* - * This file is part of the SPLINTER library. - * Copyright (C) 2012 Bjarne Grimstad (bjarne.grimstad@gmail.com). - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -#ifndef SPLINTER_SERIALIZER_H -#define SPLINTER_SERIALIZER_H - -#include -#include -#include -#include "definitions.h" -#include -#include -#include - -namespace SPLINTER -{ - -class DataPoint; -class DataTable; -class BSpline; -class BSplineBasis; -class BSplineBasis1D; - -/** - * Class for serialization - * NOTE: member variables must be serialized and deserialized in the same order. - * NOTE2: Serialization / deserialization of SparseMatrix/SparseVector works by first converting to - * DenseMatrix/DenseVector and vice versa. - */ -class Serializer -{ -public: - Serializer(); - Serializer(const std::string &fileName); - - virtual ~Serializer() {} - - // Serialize obj into the internal stream - template - void serialize(const T &obj); - - template - void deserialize(T &obj); - - template - void deserialize(std::vector &obj); - - template - void deserialize(std::set &obj); - - template - void deserialize(std::multiset &obj); - - void deserialize(DenseMatrix &obj); - void deserialize(DenseVector &obj); - void deserialize(SparseMatrix &obj); - void deserialize(SparseVector &obj); - - void deserialize(DataPoint &obj); - void deserialize(DataTable &obj); - void deserialize(BSpline &obj); - void deserialize(BSplineBasis &obj); - void deserialize(BSplineBasis1D &obj); - - // Save the serialized stream to fileName - void saveToFile(const std::string &fileName); - - // Load fileName into the internal stream - void loadFromFile(const std::string &fileName); - - template - static size_t get_size(const T &obj); - - template - static size_t get_size(const std::vector &obj); - - template - static size_t get_size(const std::set &obj); - - template - static size_t get_size(const std::multiset &obj); - - static size_t get_size(const DenseMatrix &obj); - static size_t get_size(const DenseVector &obj); - static size_t get_size(const SparseMatrix &obj); - static size_t get_size(const SparseVector &obj); - - static size_t get_size(const DataPoint &obj); - static size_t get_size(const DataTable &obj); - static size_t get_size(const BSpline &obj); - static size_t get_size(const BSplineBasis &obj); - static size_t get_size(const BSplineBasis1D &obj); - -protected: - template - void _serialize(const T &obj); - - template - void _serialize(const std::vector &obj); - - template - void _serialize(const std::set &obj); - - template - void _serialize(const std::multiset &obj); - - void _serialize(const DenseMatrix &obj); - void _serialize(const DenseVector &obj); - void _serialize(const SparseMatrix &obj); - void _serialize(const SparseVector &obj); - - void _serialize(const DataPoint &obj); - void _serialize(const DataTable &obj); - void _serialize(const BSpline &obj); - void _serialize(const BSplineBasis &obj); - void _serialize(const BSplineBasis1D &obj); - - typedef std::vector StreamType; - StreamType stream; - - // Where we are when serializing - StreamType::iterator write; - - // Where we are when deserializing - StreamType::const_iterator read; - -}; - - -template -void Serializer::serialize(const T &obj) -{ - // We can't set write to stream.end() here because the call - // to stream.resize() below may invalidate iterators - int writeIndex = stream.size(); - - // Increase the size of the stream so it can hold the object - stream.resize(stream.size() + get_size(obj)); - - write = stream.begin() + writeIndex; - - _serialize(obj); -} - -template -void Serializer::_serialize(const T &obj) -{ - // This should really be used to avoid simply copying complex objects that are not trivially copyable - // std::is_trivially_copyable is shipped with GCC 5 -// static_assert(std::is_trivially_copyable::value, "Missing Serializer::_serialize overload for T = "/* __PRETTY_FUNCTION__*/); - - // Get a uint8_t pointer to the object, so we can copy it into the stream - auto objPtr = reinterpret_cast(&obj); - - std::copy(objPtr, objPtr + sizeof(T), write); - - write += sizeof(T); -} - -template -void Serializer::deserialize(T &obj) -{ - // This should really be used to avoid simply copying complex objects that are not trivially copyable - // std::is_trivially_copyable is shipped with GCC 5 -// static_assert(std::is_trivially_copyable::value, "Missing Serializer::deserialize overload for T = "/* __PRETTY_FUNCTION__*/); - - if (read + sizeof(T) > stream.cend()) { - throw Exception("Serializer::deserialize: Stream is missing bytes!"); - } - - auto objPtr = reinterpret_cast(&obj); - - // Copy the data into val - std::copy(read, read + sizeof(T), objPtr); - - read += sizeof(T); -} - -template -size_t Serializer::get_size(const T &obj) -{ - // This should really be used to avoid simply copying complex objects that are not trivially copyable - // std::is_trivially_copyable is shipped with GCC 5 -// static_assert(std::is_trivially_copyable::value, "Missing Serializer::get_size overload for T = "/* __PRETTY_FUNCTION__*/); - - return sizeof(T); -} - -/* - * get_size specializations - */ -template -size_t Serializer::get_size(const std::vector &obj) -{ - size_t size = sizeof(size_t); - for(auto &elem : obj) { - size += get_size(elem); - } - - return size; -} - -template -size_t Serializer::get_size(const std::set &obj) -{ - size_t size = sizeof(size_t); - for(auto &elem : obj) { - size += get_size(elem); - } - - return size; -} - -template -size_t Serializer::get_size(const std::multiset &obj) { - size_t size = sizeof(size_t); - for (auto &elem : obj) { - size += get_size(elem); - } - - return size; -} - -/* - * _serialize specializations - */ -template -void Serializer::_serialize(const std::vector &obj) -{ - _serialize(obj.size()); - for(auto &elem : obj) - { - _serialize(elem); - } -} - -template -void Serializer::_serialize(const std::set &obj) -{ - _serialize(obj.size()); - for(auto &elem : obj) - { - _serialize(elem); - } -} - -template -void Serializer::_serialize(const std::multiset &obj) -{ - _serialize(obj.size()); - for(auto &elem : obj) - { - _serialize(elem); - } -} - - -/* - * deserialize specializations - */ -template -void Serializer::deserialize(std::vector &obj) -{ - size_t size; deserialize(size); - obj.resize(size); - - for (auto &elem : obj) - { - deserialize(elem); - } -} - -template -void Serializer::deserialize(std::set &obj) -{ - size_t size; deserialize(size); - - T elem; - for(size_t i = 0; i < size; ++i) - { - deserialize(elem); - obj.insert(elem); - } -} - -template -void Serializer::deserialize(std::multiset &obj) -{ - size_t size; deserialize(size); - - T elem; - for (size_t i = 0; i < size; ++i) - { - deserialize(elem); - obj.insert(elem); - } -} - - -} // namespace SPLINTER - -#endif // SPLINTER_SERIALIZER_H diff --git a/splinter/src/Cholesky/LDLT.h b/splinter/src/Cholesky/LDLT.h deleted file mode 100644 index abd30bd916..0000000000 --- a/splinter/src/Cholesky/LDLT.h +++ /dev/null @@ -1,611 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2011 Gael Guennebaud -// Copyright (C) 2009 Keir Mierle -// Copyright (C) 2009 Benoit Jacob -// Copyright (C) 2011 Timothy E. Holy -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_LDLT_H -#define EIGEN_LDLT_H - -namespace Eigen { - -namespace internal { - template struct LDLT_Traits; - - // PositiveSemiDef means positive semi-definite and non-zero; same for NegativeSemiDef - enum SignMatrix { PositiveSemiDef, NegativeSemiDef, ZeroSign, Indefinite }; -} - -/** \ingroup Cholesky_Module - * - * \class LDLT - * - * \brief Robust Cholesky decomposition of a matrix with pivoting - * - * \param MatrixType the type of the matrix of which to compute the LDL^T Cholesky decomposition - * \param UpLo the triangular part that will be used for the decompositon: Lower (default) or Upper. - * The other triangular part won't be read. - * - * Perform a robust Cholesky decomposition of a positive semidefinite or negative semidefinite - * matrix \f$ A \f$ such that \f$ A = P^TLDL^*P \f$, where P is a permutation matrix, L - * is lower triangular with a unit diagonal and D is a diagonal matrix. - * - * The decomposition uses pivoting to ensure stability, so that L will have - * zeros in the bottom right rank(A) - n submatrix. Avoiding the square root - * on D also stabilizes the computation. - * - * Remember that Cholesky decompositions are not rank-revealing. Also, do not use a Cholesky - * decomposition to determine whether a system of equations has a solution. - * - * \sa MatrixBase::ldlt(), class LLT - */ -template class LDLT -{ - public: - typedef _MatrixType MatrixType; - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime, - Options = MatrixType::Options & ~RowMajorBit, // these are the options for the TmpMatrixType, we need a ColMajor matrix here! - MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, - UpLo = _UpLo - }; - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef typename MatrixType::Index Index; - typedef Matrix TmpMatrixType; - - typedef Transpositions TranspositionType; - typedef PermutationMatrix PermutationType; - - typedef internal::LDLT_Traits Traits; - - /** \brief Default Constructor. - * - * The default constructor is useful in cases in which the user intends to - * perform decompositions via LDLT::compute(const MatrixType&). - */ - LDLT() - : m_matrix(), - m_transpositions(), - m_sign(internal::ZeroSign), - m_isInitialized(false) - {} - - /** \brief Default Constructor with memory preallocation - * - * Like the default constructor but with preallocation of the internal data - * according to the specified problem \a size. - * \sa LDLT() - */ - LDLT(Index size) - : m_matrix(size, size), - m_transpositions(size), - m_temporary(size), - m_sign(internal::ZeroSign), - m_isInitialized(false) - {} - - /** \brief Constructor with decomposition - * - * This calculates the decomposition for the input \a matrix. - * \sa LDLT(Index size) - */ - LDLT(const MatrixType& matrix) - : m_matrix(matrix.rows(), matrix.cols()), - m_transpositions(matrix.rows()), - m_temporary(matrix.rows()), - m_sign(internal::ZeroSign), - m_isInitialized(false) - { - compute(matrix); - } - - /** Clear any existing decomposition - * \sa rankUpdate(w,sigma) - */ - void setZero() - { - m_isInitialized = false; - } - - /** \returns a view of the upper triangular matrix U */ - inline typename Traits::MatrixU matrixU() const - { - eigen_assert(m_isInitialized && "LDLT is not initialized."); - return Traits::getU(m_matrix); - } - - /** \returns a view of the lower triangular matrix L */ - inline typename Traits::MatrixL matrixL() const - { - eigen_assert(m_isInitialized && "LDLT is not initialized."); - return Traits::getL(m_matrix); - } - - /** \returns the permutation matrix P as a transposition sequence. - */ - inline const TranspositionType& transpositionsP() const - { - eigen_assert(m_isInitialized && "LDLT is not initialized."); - return m_transpositions; - } - - /** \returns the coefficients of the diagonal matrix D */ - inline Diagonal vectorD() const - { - eigen_assert(m_isInitialized && "LDLT is not initialized."); - return m_matrix.diagonal(); - } - - /** \returns true if the matrix is positive (semidefinite) */ - inline bool isPositive() const - { - eigen_assert(m_isInitialized && "LDLT is not initialized."); - return m_sign == internal::PositiveSemiDef || m_sign == internal::ZeroSign; - } - - #ifdef EIGEN2_SUPPORT - inline bool isPositiveDefinite() const - { - return isPositive(); - } - #endif - - /** \returns true if the matrix is negative (semidefinite) */ - inline bool isNegative(void) const - { - eigen_assert(m_isInitialized && "LDLT is not initialized."); - return m_sign == internal::NegativeSemiDef || m_sign == internal::ZeroSign; - } - - /** \returns a solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * This function also supports in-place solves using the syntax x = decompositionObject.solve(x) . - * - * \note_about_checking_solutions - * - * More precisely, this method solves \f$ A x = b \f$ using the decomposition \f$ A = P^T L D L^* P \f$ - * by solving the systems \f$ P^T y_1 = b \f$, \f$ L y_2 = y_1 \f$, \f$ D y_3 = y_2 \f$, - * \f$ L^* y_4 = y_3 \f$ and \f$ P x = y_4 \f$ in succession. If the matrix \f$ A \f$ is singular, then - * \f$ D \f$ will also be singular (all the other matrices are invertible). In that case, the - * least-square solution of \f$ D y_3 = y_2 \f$ is computed. This does not mean that this function - * computes the least-square solution of \f$ A x = b \f$ is \f$ A \f$ is singular. - * - * \sa MatrixBase::ldlt() - */ - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "LDLT is not initialized."); - eigen_assert(m_matrix.rows()==b.rows() - && "LDLT::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); - } - - #ifdef EIGEN2_SUPPORT - template - bool solve(const MatrixBase& b, ResultType *result) const - { - *result = this->solve(b); - return true; - } - #endif - - template - bool solveInPlace(MatrixBase &bAndX) const; - - LDLT& compute(const MatrixType& matrix); - - template - LDLT& rankUpdate(const MatrixBase& w, const RealScalar& alpha=1); - - /** \returns the internal LDLT decomposition matrix - * - * TODO: document the storage layout - */ - inline const MatrixType& matrixLDLT() const - { - eigen_assert(m_isInitialized && "LDLT is not initialized."); - return m_matrix; - } - - MatrixType reconstructedMatrix() const; - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - - /** \brief Reports whether previous computation was successful. - * - * \returns \c Success if computation was succesful, - * \c NumericalIssue if the matrix.appears to be negative. - */ - ComputationInfo info() const - { - eigen_assert(m_isInitialized && "LDLT is not initialized."); - return Success; - } - - protected: - - static void check_template_parameters() - { - EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); - } - - /** \internal - * Used to compute and store the Cholesky decomposition A = L D L^* = U^* D U. - * The strict upper part is used during the decomposition, the strict lower - * part correspond to the coefficients of L (its diagonal is equal to 1 and - * is not stored), and the diagonal entries correspond to D. - */ - MatrixType m_matrix; - TranspositionType m_transpositions; - TmpMatrixType m_temporary; - internal::SignMatrix m_sign; - bool m_isInitialized; -}; - -namespace internal { - -template struct ldlt_inplace; - -template<> struct ldlt_inplace -{ - template - static bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, SignMatrix& sign) - { - using std::abs; - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::RealScalar RealScalar; - typedef typename MatrixType::Index Index; - eigen_assert(mat.rows()==mat.cols()); - const Index size = mat.rows(); - - if (size <= 1) - { - transpositions.setIdentity(); - if (numext::real(mat.coeff(0,0)) > 0) sign = PositiveSemiDef; - else if (numext::real(mat.coeff(0,0)) < 0) sign = NegativeSemiDef; - else sign = ZeroSign; - return true; - } - - for (Index k = 0; k < size; ++k) - { - // Find largest diagonal element - Index index_of_biggest_in_corner; - mat.diagonal().tail(size-k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner); - index_of_biggest_in_corner += k; - - transpositions.coeffRef(k) = index_of_biggest_in_corner; - if(k != index_of_biggest_in_corner) - { - // apply the transposition while taking care to consider only - // the lower triangular part - Index s = size-index_of_biggest_in_corner-1; // trailing size after the biggest element - mat.row(k).head(k).swap(mat.row(index_of_biggest_in_corner).head(k)); - mat.col(k).tail(s).swap(mat.col(index_of_biggest_in_corner).tail(s)); - std::swap(mat.coeffRef(k,k),mat.coeffRef(index_of_biggest_in_corner,index_of_biggest_in_corner)); - for(int i=k+1;i::IsComplex) - mat.coeffRef(index_of_biggest_in_corner,k) = numext::conj(mat.coeff(index_of_biggest_in_corner,k)); - } - - // partition the matrix: - // A00 | - | - - // lu = A10 | A11 | - - // A20 | A21 | A22 - Index rs = size - k - 1; - Block A21(mat,k+1,k,rs,1); - Block A10(mat,k,0,1,k); - Block A20(mat,k+1,0,rs,k); - - if(k>0) - { - temp.head(k) = mat.diagonal().real().head(k).asDiagonal() * A10.adjoint(); - mat.coeffRef(k,k) -= (A10 * temp.head(k)).value(); - if(rs>0) - A21.noalias() -= A20 * temp.head(k); - } - - // In some previous versions of Eigen (e.g., 3.2.1), the scaling was omitted if the pivot - // was smaller than the cutoff value. However, soince LDLT is not rank-revealing - // we should only make sure we do not introduce INF or NaN values. - // LAPACK also uses 0 as the cutoff value. - RealScalar realAkk = numext::real(mat.coeffRef(k,k)); - if((rs>0) && (abs(realAkk) > RealScalar(0))) - A21 /= realAkk; - - if (sign == PositiveSemiDef) { - if (realAkk < 0) sign = Indefinite; - } else if (sign == NegativeSemiDef) { - if (realAkk > 0) sign = Indefinite; - } else if (sign == ZeroSign) { - if (realAkk > 0) sign = PositiveSemiDef; - else if (realAkk < 0) sign = NegativeSemiDef; - } - } - - return true; - } - - // Reference for the algorithm: Davis and Hager, "Multiple Rank - // Modifications of a Sparse Cholesky Factorization" (Algorithm 1) - // Trivial rearrangements of their computations (Timothy E. Holy) - // allow their algorithm to work for rank-1 updates even if the - // original matrix is not of full rank. - // Here only rank-1 updates are implemented, to reduce the - // requirement for intermediate storage and improve accuracy - template - static bool updateInPlace(MatrixType& mat, MatrixBase& w, const typename MatrixType::RealScalar& sigma=1) - { - using numext::isfinite; - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::RealScalar RealScalar; - typedef typename MatrixType::Index Index; - - const Index size = mat.rows(); - eigen_assert(mat.cols() == size && w.size()==size); - - RealScalar alpha = 1; - - // Apply the update - for (Index j = 0; j < size; j++) - { - // Check for termination due to an original decomposition of low-rank - if (!(isfinite)(alpha)) - break; - - // Update the diagonal terms - RealScalar dj = numext::real(mat.coeff(j,j)); - Scalar wj = w.coeff(j); - RealScalar swj2 = sigma*numext::abs2(wj); - RealScalar gamma = dj*alpha + swj2; - - mat.coeffRef(j,j) += swj2/alpha; - alpha += swj2/dj; - - - // Update the terms of L - Index rs = size-j-1; - w.tail(rs) -= wj * mat.col(j).tail(rs); - if(gamma != 0) - mat.col(j).tail(rs) += (sigma*numext::conj(wj)/gamma)*w.tail(rs); - } - return true; - } - - template - static bool update(MatrixType& mat, const TranspositionType& transpositions, Workspace& tmp, const WType& w, const typename MatrixType::RealScalar& sigma=1) - { - // Apply the permutation to the input w - tmp = transpositions * w; - - return ldlt_inplace::updateInPlace(mat,tmp,sigma); - } -}; - -template<> struct ldlt_inplace -{ - template - static EIGEN_STRONG_INLINE bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, SignMatrix& sign) - { - Transpose matt(mat); - return ldlt_inplace::unblocked(matt, transpositions, temp, sign); - } - - template - static EIGEN_STRONG_INLINE bool update(MatrixType& mat, TranspositionType& transpositions, Workspace& tmp, WType& w, const typename MatrixType::RealScalar& sigma=1) - { - Transpose matt(mat); - return ldlt_inplace::update(matt, transpositions, tmp, w.conjugate(), sigma); - } -}; - -template struct LDLT_Traits -{ - typedef const TriangularView MatrixL; - typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m; } - static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } -}; - -template struct LDLT_Traits -{ - typedef const TriangularView MatrixL; - typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m.adjoint(); } - static inline MatrixU getU(const MatrixType& m) { return m; } -}; - -} // end namespace internal - -/** Compute / recompute the LDLT decomposition A = L D L^* = U^* D U of \a matrix - */ -template -LDLT& LDLT::compute(const MatrixType& a) -{ - check_template_parameters(); - - eigen_assert(a.rows()==a.cols()); - const Index size = a.rows(); - - m_matrix = a; - - m_transpositions.resize(size); - m_isInitialized = false; - m_temporary.resize(size); - m_sign = internal::ZeroSign; - - internal::ldlt_inplace::unblocked(m_matrix, m_transpositions, m_temporary, m_sign); - - m_isInitialized = true; - return *this; -} - -/** Update the LDLT decomposition: given A = L D L^T, efficiently compute the decomposition of A + sigma w w^T. - * \param w a vector to be incorporated into the decomposition. - * \param sigma a scalar, +1 for updates and -1 for "downdates," which correspond to removing previously-added column vectors. Optional; default value is +1. - * \sa setZero() - */ -template -template -LDLT& LDLT::rankUpdate(const MatrixBase& w, const typename LDLT::RealScalar& sigma) -{ - const Index size = w.rows(); - if (m_isInitialized) - { - eigen_assert(m_matrix.rows()==size); - } - else - { - m_matrix.resize(size,size); - m_matrix.setZero(); - m_transpositions.resize(size); - for (Index i = 0; i < size; i++) - m_transpositions.coeffRef(i) = i; - m_temporary.resize(size); - m_sign = sigma>=0 ? internal::PositiveSemiDef : internal::NegativeSemiDef; - m_isInitialized = true; - } - - internal::ldlt_inplace::update(m_matrix, m_transpositions, m_temporary, w, sigma); - - return *this; -} - -namespace internal { -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef LDLT<_MatrixType,_UpLo> LDLTType; - EIGEN_MAKE_SOLVE_HELPERS(LDLTType,Rhs) - - template void evalTo(Dest& dst) const - { - eigen_assert(rhs().rows() == dec().matrixLDLT().rows()); - // dst = P b - dst = dec().transpositionsP() * rhs(); - - // dst = L^-1 (P b) - dec().matrixL().solveInPlace(dst); - - // dst = D^-1 (L^-1 P b) - // more precisely, use pseudo-inverse of D (see bug 241) - using std::abs; - using std::max; - typedef typename LDLTType::MatrixType MatrixType; - typedef typename LDLTType::RealScalar RealScalar; - const typename Diagonal::RealReturnType vectorD(dec().vectorD()); - // In some previous versions, tolerance was set to the max of 1/highest and the maximal diagonal entry * epsilon - // as motivated by LAPACK's xGELSS: - // RealScalar tolerance = (max)(vectorD.array().abs().maxCoeff() *NumTraits::epsilon(),RealScalar(1) / NumTraits::highest()); - // However, LDLT is not rank revealing, and so adjusting the tolerance wrt to the highest - // diagonal element is not well justified and to numerical issues in some cases. - // Moreover, Lapack's xSYTRS routines use 0 for the tolerance. - RealScalar tolerance = RealScalar(1) / NumTraits::highest(); - - for (Index i = 0; i < vectorD.size(); ++i) { - if(abs(vectorD(i)) > tolerance) - dst.row(i) /= vectorD(i); - else - dst.row(i).setZero(); - } - - // dst = L^-T (D^-1 L^-1 P b) - dec().matrixU().solveInPlace(dst); - - // dst = P^-1 (L^-T D^-1 L^-1 P b) = A^-1 b - dst = dec().transpositionsP().transpose() * dst; - } -}; -} - -/** \internal use x = ldlt_object.solve(x); - * - * This is the \em in-place version of solve(). - * - * \param bAndX represents both the right-hand side matrix b and result x. - * - * \returns true always! If you need to check for existence of solutions, use another decomposition like LU, QR, or SVD. - * - * This version avoids a copy when the right hand side matrix b is not - * needed anymore. - * - * \sa LDLT::solve(), MatrixBase::ldlt() - */ -template -template -bool LDLT::solveInPlace(MatrixBase &bAndX) const -{ - eigen_assert(m_isInitialized && "LDLT is not initialized."); - eigen_assert(m_matrix.rows() == bAndX.rows()); - - bAndX = this->solve(bAndX); - - return true; -} - -/** \returns the matrix represented by the decomposition, - * i.e., it returns the product: P^T L D L^* P. - * This function is provided for debug purpose. */ -template -MatrixType LDLT::reconstructedMatrix() const -{ - eigen_assert(m_isInitialized && "LDLT is not initialized."); - const Index size = m_matrix.rows(); - MatrixType res(size,size); - - // P - res.setIdentity(); - res = transpositionsP() * res; - // L^* P - res = matrixU() * res; - // D(L^*P) - res = vectorD().real().asDiagonal() * res; - // L(DL^*P) - res = matrixL() * res; - // P^T (LDL^*P) - res = transpositionsP().transpose() * res; - - return res; -} - -/** \cholesky_module - * \returns the Cholesky decomposition with full pivoting without square root of \c *this - */ -template -inline const LDLT::PlainObject, UpLo> -SelfAdjointView::ldlt() const -{ - return LDLT(m_matrix); -} - -/** \cholesky_module - * \returns the Cholesky decomposition with full pivoting without square root of \c *this - */ -template -inline const LDLT::PlainObject> -MatrixBase::ldlt() const -{ - return LDLT(derived()); -} - -} // end namespace Eigen - -#endif // EIGEN_LDLT_H diff --git a/splinter/src/Cholesky/LLT.h b/splinter/src/Cholesky/LLT.h deleted file mode 100644 index 7c11a2dc29..0000000000 --- a/splinter/src/Cholesky/LLT.h +++ /dev/null @@ -1,498 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_LLT_H -#define EIGEN_LLT_H - -namespace Eigen { - -namespace internal{ -template struct LLT_Traits; -} - -/** \ingroup Cholesky_Module - * - * \class LLT - * - * \brief Standard Cholesky decomposition (LL^T) of a matrix and associated features - * - * \param MatrixType the type of the matrix of which we are computing the LL^T Cholesky decomposition - * \param UpLo the triangular part that will be used for the decompositon: Lower (default) or Upper. - * The other triangular part won't be read. - * - * This class performs a LL^T Cholesky decomposition of a symmetric, positive definite - * matrix A such that A = LL^* = U^*U, where L is lower triangular. - * - * While the Cholesky decomposition is particularly useful to solve selfadjoint problems like D^*D x = b, - * for that purpose, we recommend the Cholesky decomposition without square root which is more stable - * and even faster. Nevertheless, this standard Cholesky decomposition remains useful in many other - * situations like generalised eigen problems with hermitian matrices. - * - * Remember that Cholesky decompositions are not rank-revealing. This LLT decomposition is only stable on positive definite matrices, - * use LDLT instead for the semidefinite case. Also, do not use a Cholesky decomposition to determine whether a system of equations - * has a solution. - * - * Example: \include LLT_example.cpp - * Output: \verbinclude LLT_example.out - * - * \sa MatrixBase::llt(), class LDLT - */ - /* HEY THIS DOX IS DISABLED BECAUSE THERE's A BUG EITHER HERE OR IN LDLT ABOUT THAT (OR BOTH) - * Note that during the decomposition, only the upper triangular part of A is considered. Therefore, - * the strict lower part does not have to store correct values. - */ -template class LLT -{ - public: - typedef _MatrixType MatrixType; - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime, - Options = MatrixType::Options, - MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime - }; - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef typename MatrixType::Index Index; - - enum { - PacketSize = internal::packet_traits::size, - AlignmentMask = int(PacketSize)-1, - UpLo = _UpLo - }; - - typedef internal::LLT_Traits Traits; - - /** - * \brief Default Constructor. - * - * The default constructor is useful in cases in which the user intends to - * perform decompositions via LLT::compute(const MatrixType&). - */ - LLT() : m_matrix(), m_isInitialized(false) {} - - /** \brief Default Constructor with memory preallocation - * - * Like the default constructor but with preallocation of the internal data - * according to the specified problem \a size. - * \sa LLT() - */ - LLT(Index size) : m_matrix(size, size), - m_isInitialized(false) {} - - LLT(const MatrixType& matrix) - : m_matrix(matrix.rows(), matrix.cols()), - m_isInitialized(false) - { - compute(matrix); - } - - /** \returns a view of the upper triangular matrix U */ - inline typename Traits::MatrixU matrixU() const - { - eigen_assert(m_isInitialized && "LLT is not initialized."); - return Traits::getU(m_matrix); - } - - /** \returns a view of the lower triangular matrix L */ - inline typename Traits::MatrixL matrixL() const - { - eigen_assert(m_isInitialized && "LLT is not initialized."); - return Traits::getL(m_matrix); - } - - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * Since this LLT class assumes anyway that the matrix A is invertible, the solution - * theoretically exists and is unique regardless of b. - * - * Example: \include LLT_solve.cpp - * Output: \verbinclude LLT_solve.out - * - * \sa solveInPlace(), MatrixBase::llt() - */ - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "LLT is not initialized."); - eigen_assert(m_matrix.rows()==b.rows() - && "LLT::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); - } - - #ifdef EIGEN2_SUPPORT - template - bool solve(const MatrixBase& b, ResultType *result) const - { - *result = this->solve(b); - return true; - } - - bool isPositiveDefinite() const { return true; } - #endif - - template - void solveInPlace(MatrixBase &bAndX) const; - - LLT& compute(const MatrixType& matrix); - - /** \returns the LLT decomposition matrix - * - * TODO: document the storage layout - */ - inline const MatrixType& matrixLLT() const - { - eigen_assert(m_isInitialized && "LLT is not initialized."); - return m_matrix; - } - - MatrixType reconstructedMatrix() const; - - - /** \brief Reports whether previous computation was successful. - * - * \returns \c Success if computation was succesful, - * \c NumericalIssue if the matrix.appears to be negative. - */ - ComputationInfo info() const - { - eigen_assert(m_isInitialized && "LLT is not initialized."); - return m_info; - } - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - - template - LLT rankUpdate(const VectorType& vec, const RealScalar& sigma = 1); - - protected: - - static void check_template_parameters() - { - EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); - } - - /** \internal - * Used to compute and store L - * The strict upper part is not used and even not initialized. - */ - MatrixType m_matrix; - bool m_isInitialized; - ComputationInfo m_info; -}; - -namespace internal { - -template struct llt_inplace; - -template -static typename MatrixType::Index llt_rank_update_lower(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) -{ - using std::sqrt; - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::RealScalar RealScalar; - typedef typename MatrixType::Index Index; - typedef typename MatrixType::ColXpr ColXpr; - typedef typename internal::remove_all::type ColXprCleaned; - typedef typename ColXprCleaned::SegmentReturnType ColXprSegment; - typedef Matrix TempVectorType; - typedef typename TempVectorType::SegmentReturnType TempVecSegment; - - Index n = mat.cols(); - eigen_assert(mat.rows()==n && vec.size()==n); - - TempVectorType temp; - - if(sigma>0) - { - // This version is based on Givens rotations. - // It is faster than the other one below, but only works for updates, - // i.e., for sigma > 0 - temp = sqrt(sigma) * vec; - - for(Index i=0; i g; - g.makeGivens(mat(i,i), -temp(i), &mat(i,i)); - - Index rs = n-i-1; - if(rs>0) - { - ColXprSegment x(mat.col(i).tail(rs)); - TempVecSegment y(temp.tail(rs)); - apply_rotation_in_the_plane(x, y, g); - } - } - } - else - { - temp = vec; - RealScalar beta = 1; - for(Index j=0; j struct llt_inplace -{ - typedef typename NumTraits::Real RealScalar; - template - static typename MatrixType::Index unblocked(MatrixType& mat) - { - using std::sqrt; - typedef typename MatrixType::Index Index; - - eigen_assert(mat.rows()==mat.cols()); - const Index size = mat.rows(); - for(Index k = 0; k < size; ++k) - { - Index rs = size-k-1; // remaining size - - Block A21(mat,k+1,k,rs,1); - Block A10(mat,k,0,1,k); - Block A20(mat,k+1,0,rs,k); - - RealScalar x = numext::real(mat.coeff(k,k)); - if (k>0) x -= A10.squaredNorm(); - if (x<=RealScalar(0)) - return k; - mat.coeffRef(k,k) = x = sqrt(x); - if (k>0 && rs>0) A21.noalias() -= A20 * A10.adjoint(); - if (rs>0) A21 /= x; - } - return -1; - } - - template - static typename MatrixType::Index blocked(MatrixType& m) - { - typedef typename MatrixType::Index Index; - eigen_assert(m.rows()==m.cols()); - Index size = m.rows(); - if(size<32) - return unblocked(m); - - Index blockSize = size/8; - blockSize = (blockSize/16)*16; - blockSize = (std::min)((std::max)(blockSize,Index(8)), Index(128)); - - for (Index k=0; k A11(m,k, k, bs,bs); - Block A21(m,k+bs,k, rs,bs); - Block A22(m,k+bs,k+bs,rs,rs); - - Index ret; - if((ret=unblocked(A11))>=0) return k+ret; - if(rs>0) A11.adjoint().template triangularView().template solveInPlace(A21); - if(rs>0) A22.template selfadjointView().rankUpdate(A21,-1); // bottleneck - } - return -1; - } - - template - static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) - { - return Eigen::internal::llt_rank_update_lower(mat, vec, sigma); - } -}; - -template struct llt_inplace -{ - typedef typename NumTraits::Real RealScalar; - - template - static EIGEN_STRONG_INLINE typename MatrixType::Index unblocked(MatrixType& mat) - { - Transpose matt(mat); - return llt_inplace::unblocked(matt); - } - template - static EIGEN_STRONG_INLINE typename MatrixType::Index blocked(MatrixType& mat) - { - Transpose matt(mat); - return llt_inplace::blocked(matt); - } - template - static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) - { - Transpose matt(mat); - return llt_inplace::rankUpdate(matt, vec.conjugate(), sigma); - } -}; - -template struct LLT_Traits -{ - typedef const TriangularView MatrixL; - typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m; } - static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } - static bool inplace_decomposition(MatrixType& m) - { return llt_inplace::blocked(m)==-1; } -}; - -template struct LLT_Traits -{ - typedef const TriangularView MatrixL; - typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m.adjoint(); } - static inline MatrixU getU(const MatrixType& m) { return m; } - static bool inplace_decomposition(MatrixType& m) - { return llt_inplace::blocked(m)==-1; } -}; - -} // end namespace internal - -/** Computes / recomputes the Cholesky decomposition A = LL^* = U^*U of \a matrix - * - * \returns a reference to *this - * - * Example: \include TutorialLinAlgComputeTwice.cpp - * Output: \verbinclude TutorialLinAlgComputeTwice.out - */ -template -LLT& LLT::compute(const MatrixType& a) -{ - check_template_parameters(); - - eigen_assert(a.rows()==a.cols()); - const Index size = a.rows(); - m_matrix.resize(size, size); - m_matrix = a; - - m_isInitialized = true; - bool ok = Traits::inplace_decomposition(m_matrix); - m_info = ok ? Success : NumericalIssue; - - return *this; -} - -/** Performs a rank one update (or dowdate) of the current decomposition. - * If A = LL^* before the rank one update, - * then after it we have LL^* = A + sigma * v v^* where \a v must be a vector - * of same dimension. - */ -template -template -LLT<_MatrixType,_UpLo> LLT<_MatrixType,_UpLo>::rankUpdate(const VectorType& v, const RealScalar& sigma) -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(VectorType); - eigen_assert(v.size()==m_matrix.cols()); - eigen_assert(m_isInitialized); - if(internal::llt_inplace::rankUpdate(m_matrix,v,sigma)>=0) - m_info = NumericalIssue; - else - m_info = Success; - - return *this; -} - -namespace internal { -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef LLT<_MatrixType,UpLo> LLTType; - EIGEN_MAKE_SOLVE_HELPERS(LLTType,Rhs) - - template void evalTo(Dest& dst) const - { - dst = rhs(); - dec().solveInPlace(dst); - } -}; -} - -/** \internal use x = llt_object.solve(x); - * - * This is the \em in-place version of solve(). - * - * \param bAndX represents both the right-hand side matrix b and result x. - * - * \returns true always! If you need to check for existence of solutions, use another decomposition like LU, QR, or SVD. - * - * This version avoids a copy when the right hand side matrix b is not - * needed anymore. - * - * \sa LLT::solve(), MatrixBase::llt() - */ -template -template -void LLT::solveInPlace(MatrixBase &bAndX) const -{ - eigen_assert(m_isInitialized && "LLT is not initialized."); - eigen_assert(m_matrix.rows()==bAndX.rows()); - matrixL().solveInPlace(bAndX); - matrixU().solveInPlace(bAndX); -} - -/** \returns the matrix represented by the decomposition, - * i.e., it returns the product: L L^*. - * This function is provided for debug purpose. */ -template -MatrixType LLT::reconstructedMatrix() const -{ - eigen_assert(m_isInitialized && "LLT is not initialized."); - return matrixL() * matrixL().adjoint().toDenseMatrix(); -} - -/** \cholesky_module - * \returns the LLT decomposition of \c *this - */ -template -inline const LLT::PlainObject> -MatrixBase::llt() const -{ - return LLT(derived()); -} - -/** \cholesky_module - * \returns the LLT decomposition of \c *this - */ -template -inline const LLT::PlainObject, UpLo> -SelfAdjointView::llt() const -{ - return LLT(m_matrix); -} - -} // end namespace Eigen - -#endif // EIGEN_LLT_H diff --git a/splinter/src/Cholesky/LLT_MKL.h b/splinter/src/Cholesky/LLT_MKL.h deleted file mode 100644 index 66675d7476..0000000000 --- a/splinter/src/Cholesky/LLT_MKL.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - Copyright (c) 2011, Intel Corporation. All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of Intel Corporation nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - ******************************************************************************** - * Content : Eigen bindings to Intel(R) MKL - * LLt decomposition based on LAPACKE_?potrf function. - ******************************************************************************** -*/ - -#ifndef EIGEN_LLT_MKL_H -#define EIGEN_LLT_MKL_H - -#include "Eigen/src/Core/util/MKL_support.h" -#include - -namespace Eigen { - -namespace internal { - -template struct mkl_llt; - -#define EIGEN_MKL_LLT(EIGTYPE, MKLTYPE, MKLPREFIX) \ -template<> struct mkl_llt \ -{ \ - template \ - static inline typename MatrixType::Index potrf(MatrixType& m, char uplo) \ - { \ - lapack_int matrix_order; \ - lapack_int size, lda, info, StorageOrder; \ - EIGTYPE* a; \ - eigen_assert(m.rows()==m.cols()); \ - /* Set up parameters for ?potrf */ \ - size = m.rows(); \ - StorageOrder = MatrixType::Flags&RowMajorBit?RowMajor:ColMajor; \ - matrix_order = StorageOrder==RowMajor ? LAPACK_ROW_MAJOR : LAPACK_COL_MAJOR; \ - a = &(m.coeffRef(0,0)); \ - lda = m.outerStride(); \ -\ - info = LAPACKE_##MKLPREFIX##potrf( matrix_order, uplo, size, (MKLTYPE*)a, lda ); \ - info = (info==0) ? -1 : info>0 ? info-1 : size; \ - return info; \ - } \ -}; \ -template<> struct llt_inplace \ -{ \ - template \ - static typename MatrixType::Index blocked(MatrixType& m) \ - { \ - return mkl_llt::potrf(m, 'L'); \ - } \ - template \ - static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \ - { return Eigen::internal::llt_rank_update_lower(mat, vec, sigma); } \ -}; \ -template<> struct llt_inplace \ -{ \ - template \ - static typename MatrixType::Index blocked(MatrixType& m) \ - { \ - return mkl_llt::potrf(m, 'U'); \ - } \ - template \ - static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \ - { \ - Transpose matt(mat); \ - return llt_inplace::rankUpdate(matt, vec.conjugate(), sigma); \ - } \ -}; - -EIGEN_MKL_LLT(double, double, d) -EIGEN_MKL_LLT(float, float, s) -EIGEN_MKL_LLT(dcomplex, MKL_Complex16, z) -EIGEN_MKL_LLT(scomplex, MKL_Complex8, c) - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_LLT_MKL_H diff --git a/splinter/src/CholmodSupport/CholmodSupport.h b/splinter/src/CholmodSupport/CholmodSupport.h deleted file mode 100644 index 99dbe171c3..0000000000 --- a/splinter/src/CholmodSupport/CholmodSupport.h +++ /dev/null @@ -1,607 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_CHOLMODSUPPORT_H -#define EIGEN_CHOLMODSUPPORT_H - -namespace Eigen { - -namespace internal { - -template -void cholmod_configure_matrix(CholmodType& mat) -{ - if (internal::is_same::value) - { - mat.xtype = CHOLMOD_REAL; - mat.dtype = CHOLMOD_SINGLE; - } - else if (internal::is_same::value) - { - mat.xtype = CHOLMOD_REAL; - mat.dtype = CHOLMOD_DOUBLE; - } - else if (internal::is_same >::value) - { - mat.xtype = CHOLMOD_COMPLEX; - mat.dtype = CHOLMOD_SINGLE; - } - else if (internal::is_same >::value) - { - mat.xtype = CHOLMOD_COMPLEX; - mat.dtype = CHOLMOD_DOUBLE; - } - else - { - eigen_assert(false && "Scalar type not supported by CHOLMOD"); - } -} - -} // namespace internal - -/** Wraps the Eigen sparse matrix \a mat into a Cholmod sparse matrix object. - * Note that the data are shared. - */ -template -cholmod_sparse viewAsCholmod(SparseMatrix<_Scalar,_Options,_Index>& mat) -{ - cholmod_sparse res; - res.nzmax = mat.nonZeros(); - res.nrow = mat.rows();; - res.ncol = mat.cols(); - res.p = mat.outerIndexPtr(); - res.i = mat.innerIndexPtr(); - res.x = mat.valuePtr(); - res.z = 0; - res.sorted = 1; - if(mat.isCompressed()) - { - res.packed = 1; - res.nz = 0; - } - else - { - res.packed = 0; - res.nz = mat.innerNonZeroPtr(); - } - - res.dtype = 0; - res.stype = -1; - - if (internal::is_same<_Index,int>::value) - { - res.itype = CHOLMOD_INT; - } - else if (internal::is_same<_Index,SuiteSparse_long>::value) - { - res.itype = CHOLMOD_LONG; - } - else - { - eigen_assert(false && "Index type not supported yet"); - } - - // setup res.xtype - internal::cholmod_configure_matrix<_Scalar>(res); - - res.stype = 0; - - return res; -} - -template -const cholmod_sparse viewAsCholmod(const SparseMatrix<_Scalar,_Options,_Index>& mat) -{ - cholmod_sparse res = viewAsCholmod(mat.const_cast_derived()); - return res; -} - -/** Returns a view of the Eigen sparse matrix \a mat as Cholmod sparse matrix. - * The data are not copied but shared. */ -template -cholmod_sparse viewAsCholmod(const SparseSelfAdjointView, UpLo>& mat) -{ - cholmod_sparse res = viewAsCholmod(mat.matrix().const_cast_derived()); - - if(UpLo==Upper) res.stype = 1; - if(UpLo==Lower) res.stype = -1; - - return res; -} - -/** Returns a view of the Eigen \b dense matrix \a mat as Cholmod dense matrix. - * The data are not copied but shared. */ -template -cholmod_dense viewAsCholmod(MatrixBase& mat) -{ - EIGEN_STATIC_ASSERT((internal::traits::Flags&RowMajorBit)==0,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); - typedef typename Derived::Scalar Scalar; - - cholmod_dense res; - res.nrow = mat.rows(); - res.ncol = mat.cols(); - res.nzmax = res.nrow * res.ncol; - res.d = Derived::IsVectorAtCompileTime ? mat.derived().size() : mat.derived().outerStride(); - res.x = (void*)(mat.derived().data()); - res.z = 0; - - internal::cholmod_configure_matrix(res); - - return res; -} - -/** Returns a view of the Cholmod sparse matrix \a cm as an Eigen sparse matrix. - * The data are not copied but shared. */ -template -MappedSparseMatrix viewAsEigen(cholmod_sparse& cm) -{ - return MappedSparseMatrix - (cm.nrow, cm.ncol, static_cast(cm.p)[cm.ncol], - static_cast(cm.p), static_cast(cm.i),static_cast(cm.x) ); -} - -enum CholmodMode { - CholmodAuto, CholmodSimplicialLLt, CholmodSupernodalLLt, CholmodLDLt -}; - - -/** \ingroup CholmodSupport_Module - * \class CholmodBase - * \brief The base class for the direct Cholesky factorization of Cholmod - * \sa class CholmodSupernodalLLT, class CholmodSimplicialLDLT, class CholmodSimplicialLLT - */ -template -class CholmodBase : internal::noncopyable -{ - public: - typedef _MatrixType MatrixType; - enum { UpLo = _UpLo }; - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::RealScalar RealScalar; - typedef MatrixType CholMatrixType; - typedef typename MatrixType::Index Index; - - public: - - CholmodBase() - : m_cholmodFactor(0), m_info(Success), m_isInitialized(false) - { - m_shiftOffset[0] = m_shiftOffset[1] = RealScalar(0.0); - cholmod_start(&m_cholmod); - } - - CholmodBase(const MatrixType& matrix) - : m_cholmodFactor(0), m_info(Success), m_isInitialized(false) - { - m_shiftOffset[0] = m_shiftOffset[1] = RealScalar(0.0); - cholmod_start(&m_cholmod); - compute(matrix); - } - - ~CholmodBase() - { - if(m_cholmodFactor) - cholmod_free_factor(&m_cholmodFactor, &m_cholmod); - cholmod_finish(&m_cholmod); - } - - inline Index cols() const { return m_cholmodFactor->n; } - inline Index rows() const { return m_cholmodFactor->n; } - - Derived& derived() { return *static_cast(this); } - const Derived& derived() const { return *static_cast(this); } - - /** \brief Reports whether previous computation was successful. - * - * \returns \c Success if computation was succesful, - * \c NumericalIssue if the matrix.appears to be negative. - */ - ComputationInfo info() const - { - eigen_assert(m_isInitialized && "Decomposition is not initialized."); - return m_info; - } - - /** Computes the sparse Cholesky decomposition of \a matrix */ - Derived& compute(const MatrixType& matrix) - { - analyzePattern(matrix); - factorize(matrix); - return derived(); - } - - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "LLT is not initialized."); - eigen_assert(rows()==b.rows() - && "CholmodDecomposition::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); - } - - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::sparse_solve_retval - solve(const SparseMatrixBase& b) const - { - eigen_assert(m_isInitialized && "LLT is not initialized."); - eigen_assert(rows()==b.rows() - && "CholmodDecomposition::solve(): invalid number of rows of the right hand side matrix b"); - return internal::sparse_solve_retval(*this, b.derived()); - } - - /** Performs a symbolic decomposition on the sparsity pattern of \a matrix. - * - * This function is particularly useful when solving for several problems having the same structure. - * - * \sa factorize() - */ - void analyzePattern(const MatrixType& matrix) - { - if(m_cholmodFactor) - { - cholmod_free_factor(&m_cholmodFactor, &m_cholmod); - m_cholmodFactor = 0; - } - cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView()); - m_cholmodFactor = cholmod_analyze(&A, &m_cholmod); - - this->m_isInitialized = true; - this->m_info = Success; - m_analysisIsOk = true; - m_factorizationIsOk = false; - } - - /** Performs a numeric decomposition of \a matrix - * - * The given matrix must have the same sparsity pattern as the matrix on which the symbolic decomposition has been performed. - * - * \sa analyzePattern() - */ - void factorize(const MatrixType& matrix) - { - eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); - cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView()); - cholmod_factorize_p(&A, m_shiftOffset, 0, 0, m_cholmodFactor, &m_cholmod); - - // If the factorization failed, minor is the column at which it did. On success minor == n. - this->m_info = (m_cholmodFactor->minor == m_cholmodFactor->n ? Success : NumericalIssue); - m_factorizationIsOk = true; - } - - /** Returns a reference to the Cholmod's configuration structure to get a full control over the performed operations. - * See the Cholmod user guide for details. */ - cholmod_common& cholmod() { return m_cholmod; } - - #ifndef EIGEN_PARSED_BY_DOXYGEN - /** \internal */ - template - void _solve(const MatrixBase &b, MatrixBase &dest) const - { - eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); - const Index size = m_cholmodFactor->n; - EIGEN_UNUSED_VARIABLE(size); - eigen_assert(size==b.rows()); - - // note: cd stands for Cholmod Dense - Rhs& b_ref(b.const_cast_derived()); - cholmod_dense b_cd = viewAsCholmod(b_ref); - cholmod_dense* x_cd = cholmod_solve(CHOLMOD_A, m_cholmodFactor, &b_cd, &m_cholmod); - if(!x_cd) - { - this->m_info = NumericalIssue; - } - // TODO optimize this copy by swapping when possible (be careful with alignment, etc.) - dest = Matrix::Map(reinterpret_cast(x_cd->x),b.rows(),b.cols()); - cholmod_free_dense(&x_cd, &m_cholmod); - } - - /** \internal */ - template - void _solve(const SparseMatrix &b, SparseMatrix &dest) const - { - eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); - const Index size = m_cholmodFactor->n; - EIGEN_UNUSED_VARIABLE(size); - eigen_assert(size==b.rows()); - - // note: cs stands for Cholmod Sparse - cholmod_sparse b_cs = viewAsCholmod(b); - cholmod_sparse* x_cs = cholmod_spsolve(CHOLMOD_A, m_cholmodFactor, &b_cs, &m_cholmod); - if(!x_cs) - { - this->m_info = NumericalIssue; - } - // TODO optimize this copy by swapping when possible (be careful with alignment, etc.) - dest = viewAsEigen(*x_cs); - cholmod_free_sparse(&x_cs, &m_cholmod); - } - #endif // EIGEN_PARSED_BY_DOXYGEN - - - /** Sets the shift parameter that will be used to adjust the diagonal coefficients during the numerical factorization. - * - * During the numerical factorization, an offset term is added to the diagonal coefficients:\n - * \c d_ii = \a offset + \c d_ii - * - * The default is \a offset=0. - * - * \returns a reference to \c *this. - */ - Derived& setShift(const RealScalar& offset) - { - m_shiftOffset[0] = offset; - return derived(); - } - - template - void dumpMemory(Stream& /*s*/) - {} - - protected: - mutable cholmod_common m_cholmod; - cholmod_factor* m_cholmodFactor; - RealScalar m_shiftOffset[2]; - mutable ComputationInfo m_info; - bool m_isInitialized; - int m_factorizationIsOk; - int m_analysisIsOk; -}; - -/** \ingroup CholmodSupport_Module - * \class CholmodSimplicialLLT - * \brief A simplicial direct Cholesky (LLT) factorization and solver based on Cholmod - * - * This class allows to solve for A.X = B sparse linear problems via a simplicial LL^T Cholesky factorization - * using the Cholmod library. - * This simplicial variant is equivalent to Eigen's built-in SimplicialLLT class. Therefore, it has little practical interest. - * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices - * X and B can be either dense or sparse. - * - * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> - * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower - * or Upper. Default is Lower. - * - * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. - * - * \sa \ref TutorialSparseDirectSolvers, class CholmodSupernodalLLT, class SimplicialLLT - */ -template -class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT<_MatrixType, _UpLo> > -{ - typedef CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT> Base; - using Base::m_cholmod; - - public: - - typedef _MatrixType MatrixType; - - CholmodSimplicialLLT() : Base() { init(); } - - CholmodSimplicialLLT(const MatrixType& matrix) : Base() - { - init(); - Base::compute(matrix); - } - - ~CholmodSimplicialLLT() {} - protected: - void init() - { - m_cholmod.final_asis = 0; - m_cholmod.supernodal = CHOLMOD_SIMPLICIAL; - m_cholmod.final_ll = 1; - } -}; - - -/** \ingroup CholmodSupport_Module - * \class CholmodSimplicialLDLT - * \brief A simplicial direct Cholesky (LDLT) factorization and solver based on Cholmod - * - * This class allows to solve for A.X = B sparse linear problems via a simplicial LDL^T Cholesky factorization - * using the Cholmod library. - * This simplicial variant is equivalent to Eigen's built-in SimplicialLDLT class. Therefore, it has little practical interest. - * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices - * X and B can be either dense or sparse. - * - * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> - * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower - * or Upper. Default is Lower. - * - * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. - * - * \sa \ref TutorialSparseDirectSolvers, class CholmodSupernodalLLT, class SimplicialLDLT - */ -template -class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT<_MatrixType, _UpLo> > -{ - typedef CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT> Base; - using Base::m_cholmod; - - public: - - typedef _MatrixType MatrixType; - - CholmodSimplicialLDLT() : Base() { init(); } - - CholmodSimplicialLDLT(const MatrixType& matrix) : Base() - { - init(); - Base::compute(matrix); - } - - ~CholmodSimplicialLDLT() {} - protected: - void init() - { - m_cholmod.final_asis = 1; - m_cholmod.supernodal = CHOLMOD_SIMPLICIAL; - } -}; - -/** \ingroup CholmodSupport_Module - * \class CholmodSupernodalLLT - * \brief A supernodal Cholesky (LLT) factorization and solver based on Cholmod - * - * This class allows to solve for A.X = B sparse linear problems via a supernodal LL^T Cholesky factorization - * using the Cholmod library. - * This supernodal variant performs best on dense enough problems, e.g., 3D FEM, or very high order 2D FEM. - * The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices - * X and B can be either dense or sparse. - * - * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> - * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower - * or Upper. Default is Lower. - * - * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. - * - * \sa \ref TutorialSparseDirectSolvers - */ -template -class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT<_MatrixType, _UpLo> > -{ - typedef CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT> Base; - using Base::m_cholmod; - - public: - - typedef _MatrixType MatrixType; - - CholmodSupernodalLLT() : Base() { init(); } - - CholmodSupernodalLLT(const MatrixType& matrix) : Base() - { - init(); - Base::compute(matrix); - } - - ~CholmodSupernodalLLT() {} - protected: - void init() - { - m_cholmod.final_asis = 1; - m_cholmod.supernodal = CHOLMOD_SUPERNODAL; - } -}; - -/** \ingroup CholmodSupport_Module - * \class CholmodDecomposition - * \brief A general Cholesky factorization and solver based on Cholmod - * - * This class allows to solve for A.X = B sparse linear problems via a LL^T or LDL^T Cholesky factorization - * using the Cholmod library. The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices - * X and B can be either dense or sparse. - * - * This variant permits to change the underlying Cholesky method at runtime. - * On the other hand, it does not provide access to the result of the factorization. - * The default is to let Cholmod automatically choose between a simplicial and supernodal factorization. - * - * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> - * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower - * or Upper. Default is Lower. - * - * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. - * - * \sa \ref TutorialSparseDirectSolvers - */ -template -class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecomposition<_MatrixType, _UpLo> > -{ - typedef CholmodBase<_MatrixType, _UpLo, CholmodDecomposition> Base; - using Base::m_cholmod; - - public: - - typedef _MatrixType MatrixType; - - CholmodDecomposition() : Base() { init(); } - - CholmodDecomposition(const MatrixType& matrix) : Base() - { - init(); - Base::compute(matrix); - } - - ~CholmodDecomposition() {} - - void setMode(CholmodMode mode) - { - switch(mode) - { - case CholmodAuto: - m_cholmod.final_asis = 1; - m_cholmod.supernodal = CHOLMOD_AUTO; - break; - case CholmodSimplicialLLt: - m_cholmod.final_asis = 0; - m_cholmod.supernodal = CHOLMOD_SIMPLICIAL; - m_cholmod.final_ll = 1; - break; - case CholmodSupernodalLLt: - m_cholmod.final_asis = 1; - m_cholmod.supernodal = CHOLMOD_SUPERNODAL; - break; - case CholmodLDLt: - m_cholmod.final_asis = 1; - m_cholmod.supernodal = CHOLMOD_SIMPLICIAL; - break; - default: - break; - } - } - protected: - void init() - { - m_cholmod.final_asis = 1; - m_cholmod.supernodal = CHOLMOD_AUTO; - } -}; - -namespace internal { - -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef CholmodBase<_MatrixType,_UpLo,Derived> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve(rhs(),dst); - } -}; - -template -struct sparse_solve_retval, Rhs> - : sparse_solve_retval_base, Rhs> -{ - typedef CholmodBase<_MatrixType,_UpLo,Derived> Dec; - EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve(rhs(),dst); - } -}; - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_CHOLMODSUPPORT_H diff --git a/splinter/src/Core/Array.h b/splinter/src/Core/Array.h deleted file mode 100644 index 0b9c38c821..0000000000 --- a/splinter/src/Core/Array.h +++ /dev/null @@ -1,323 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_ARRAY_H -#define EIGEN_ARRAY_H - -namespace Eigen { - -/** \class Array - * \ingroup Core_Module - * - * \brief General-purpose arrays with easy API for coefficient-wise operations - * - * The %Array class is very similar to the Matrix class. It provides - * general-purpose one- and two-dimensional arrays. The difference between the - * %Array and the %Matrix class is primarily in the API: the API for the - * %Array class provides easy access to coefficient-wise operations, while the - * API for the %Matrix class provides easy access to linear-algebra - * operations. - * - * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_ARRAY_PLUGIN. - * - * \sa \ref TutorialArrayClass, \ref TopicClassHierarchy - */ -namespace internal { -template -struct traits > : traits > -{ - typedef ArrayXpr XprKind; - typedef ArrayBase > XprBase; -}; -} - -template -class Array - : public PlainObjectBase > -{ - public: - - typedef PlainObjectBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(Array) - - enum { Options = _Options }; - typedef typename Base::PlainObject PlainObject; - - protected: - template - friend struct internal::conservative_resize_like_impl; - - using Base::m_storage; - - public: - - using Base::base; - using Base::coeff; - using Base::coeffRef; - - /** - * The usage of - * using Base::operator=; - * fails on MSVC. Since the code below is working with GCC and MSVC, we skipped - * the usage of 'using'. This should be done only for operator=. - */ - template - EIGEN_STRONG_INLINE Array& operator=(const EigenBase &other) - { - return Base::operator=(other); - } - - /** Copies the value of the expression \a other into \c *this with automatic resizing. - * - * *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized), - * it will be initialized. - * - * Note that copying a row-vector into a vector (and conversely) is allowed. - * The resizing, if any, is then done in the appropriate way so that row-vectors - * remain row-vectors and vectors remain vectors. - */ - template - EIGEN_STRONG_INLINE Array& operator=(const ArrayBase& other) - { - return Base::_set(other); - } - - /** This is a special case of the templated operator=. Its purpose is to - * prevent a default operator= from hiding the templated operator=. - */ - EIGEN_STRONG_INLINE Array& operator=(const Array& other) - { - return Base::_set(other); - } - - /** Default constructor. - * - * For fixed-size matrices, does nothing. - * - * For dynamic-size matrices, creates an empty matrix of size 0. Does not allocate any array. Such a matrix - * is called a null matrix. This constructor is the unique way to create null matrices: resizing - * a matrix to 0 is not supported. - * - * \sa resize(Index,Index) - */ - EIGEN_STRONG_INLINE Array() : Base() - { - Base::_check_template_params(); - EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED - } - -#ifndef EIGEN_PARSED_BY_DOXYGEN - // FIXME is it still needed ?? - /** \internal */ - Array(internal::constructor_without_unaligned_array_assert) - : Base(internal::constructor_without_unaligned_array_assert()) - { - Base::_check_template_params(); - EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED - } -#endif - -#ifdef EIGEN_HAVE_RVALUE_REFERENCES - Array(Array&& other) - : Base(std::move(other)) - { - Base::_check_template_params(); - if (RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic) - Base::_set_noalias(other); - } - Array& operator=(Array&& other) - { - other.swap(*this); - return *this; - } -#endif - - /** Constructs a vector or row-vector with given dimension. \only_for_vectors - * - * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, - * it is redundant to pass the dimension here, so it makes more sense to use the default - * constructor Matrix() instead. - */ - EIGEN_STRONG_INLINE explicit Array(Index dim) - : Base(dim, RowsAtCompileTime == 1 ? 1 : dim, ColsAtCompileTime == 1 ? 1 : dim) - { - Base::_check_template_params(); - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Array) - eigen_assert(dim >= 0); - eigen_assert(SizeAtCompileTime == Dynamic || SizeAtCompileTime == dim); - EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED - } - - #ifndef EIGEN_PARSED_BY_DOXYGEN - template - EIGEN_STRONG_INLINE Array(const T0& val0, const T1& val1) - { - Base::_check_template_params(); - this->template _init2(val0, val1); - } - #else - /** constructs an uninitialized matrix with \a rows rows and \a cols columns. - * - * This is useful for dynamic-size matrices. For fixed-size matrices, - * it is redundant to pass these parameters, so one should use the default constructor - * Matrix() instead. */ - Array(Index rows, Index cols); - /** constructs an initialized 2D vector with given coefficients */ - Array(const Scalar& val0, const Scalar& val1); - #endif - - /** constructs an initialized 3D vector with given coefficients */ - EIGEN_STRONG_INLINE Array(const Scalar& val0, const Scalar& val1, const Scalar& val2) - { - Base::_check_template_params(); - EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Array, 3) - m_storage.data()[0] = val0; - m_storage.data()[1] = val1; - m_storage.data()[2] = val2; - } - /** constructs an initialized 4D vector with given coefficients */ - EIGEN_STRONG_INLINE Array(const Scalar& val0, const Scalar& val1, const Scalar& val2, const Scalar& val3) - { - Base::_check_template_params(); - EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Array, 4) - m_storage.data()[0] = val0; - m_storage.data()[1] = val1; - m_storage.data()[2] = val2; - m_storage.data()[3] = val3; - } - - explicit Array(const Scalar *data); - - /** Constructor copying the value of the expression \a other */ - template - EIGEN_STRONG_INLINE Array(const ArrayBase& other) - : Base(other.rows() * other.cols(), other.rows(), other.cols()) - { - Base::_check_template_params(); - Base::_set_noalias(other); - } - /** Copy constructor */ - EIGEN_STRONG_INLINE Array(const Array& other) - : Base(other.rows() * other.cols(), other.rows(), other.cols()) - { - Base::_check_template_params(); - Base::_set_noalias(other); - } - /** Copy constructor with in-place evaluation */ - template - EIGEN_STRONG_INLINE Array(const ReturnByValue& other) - { - Base::_check_template_params(); - Base::resize(other.rows(), other.cols()); - other.evalTo(*this); - } - - /** \sa MatrixBase::operator=(const EigenBase&) */ - template - EIGEN_STRONG_INLINE Array(const EigenBase &other) - : Base(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols()) - { - Base::_check_template_params(); - Base::_resize_to_match(other); - *this = other; - } - - /** Override MatrixBase::swap() since for dynamic-sized matrices of same type it is enough to swap the - * data pointers. - */ - template - void swap(ArrayBase const & other) - { this->_swap(other.derived()); } - - inline Index innerStride() const { return 1; } - inline Index outerStride() const { return this->innerSize(); } - - #ifdef EIGEN_ARRAY_PLUGIN - #include EIGEN_ARRAY_PLUGIN - #endif - - private: - - template - friend struct internal::matrix_swap_impl; -}; - -/** \defgroup arraytypedefs Global array typedefs - * \ingroup Core_Module - * - * Eigen defines several typedef shortcuts for most common 1D and 2D array types. - * - * The general patterns are the following: - * - * \c ArrayRowsColsType where \c Rows and \c Cols can be \c 2,\c 3,\c 4 for fixed size square matrices or \c X for dynamic size, - * and where \c Type can be \c i for integer, \c f for float, \c d for double, \c cf for complex float, \c cd - * for complex double. - * - * For example, \c Array33d is a fixed-size 3x3 array type of doubles, and \c ArrayXXf is a dynamic-size matrix of floats. - * - * There are also \c ArraySizeType which are self-explanatory. For example, \c Array4cf is - * a fixed-size 1D array of 4 complex floats. - * - * \sa class Array - */ - -#define EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, Size, SizeSuffix) \ -/** \ingroup arraytypedefs */ \ -typedef Array Array##SizeSuffix##SizeSuffix##TypeSuffix; \ -/** \ingroup arraytypedefs */ \ -typedef Array Array##SizeSuffix##TypeSuffix; - -#define EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, Size) \ -/** \ingroup arraytypedefs */ \ -typedef Array Array##Size##X##TypeSuffix; \ -/** \ingroup arraytypedefs */ \ -typedef Array Array##X##Size##TypeSuffix; - -#define EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(Type, TypeSuffix) \ -EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 2, 2) \ -EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 3, 3) \ -EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 4, 4) \ -EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, Dynamic, X) \ -EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 2) \ -EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 3) \ -EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 4) - -EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(int, i) -EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(float, f) -EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(double, d) -EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(std::complex, cf) -EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(std::complex, cd) - -#undef EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES -#undef EIGEN_MAKE_ARRAY_TYPEDEFS - -#undef EIGEN_MAKE_ARRAY_TYPEDEFS_LARGE - -#define EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, SizeSuffix) \ -using Eigen::Matrix##SizeSuffix##TypeSuffix; \ -using Eigen::Vector##SizeSuffix##TypeSuffix; \ -using Eigen::RowVector##SizeSuffix##TypeSuffix; - -#define EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(TypeSuffix) \ -EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 2) \ -EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 3) \ -EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 4) \ -EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, X) \ - -#define EIGEN_USING_ARRAY_TYPEDEFS \ -EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(i) \ -EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(f) \ -EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(d) \ -EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(cf) \ -EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(cd) - -} // end namespace Eigen - -#endif // EIGEN_ARRAY_H diff --git a/splinter/src/Core/ArrayBase.h b/splinter/src/Core/ArrayBase.h deleted file mode 100644 index 33ff553712..0000000000 --- a/splinter/src/Core/ArrayBase.h +++ /dev/null @@ -1,226 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_ARRAYBASE_H -#define EIGEN_ARRAYBASE_H - -namespace Eigen { - -template class MatrixWrapper; - -/** \class ArrayBase - * \ingroup Core_Module - * - * \brief Base class for all 1D and 2D array, and related expressions - * - * An array is similar to a dense vector or matrix. While matrices are mathematical - * objects with well defined linear algebra operators, an array is just a collection - * of scalar values arranged in a one or two dimensionnal fashion. As the main consequence, - * all operations applied to an array are performed coefficient wise. Furthermore, - * arrays support scalar math functions of the c++ standard library (e.g., std::sin(x)), and convenient - * constructors allowing to easily write generic code working for both scalar values - * and arrays. - * - * This class is the base that is inherited by all array expression types. - * - * \tparam Derived is the derived type, e.g., an array or an expression type. - * - * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_ARRAYBASE_PLUGIN. - * - * \sa class MatrixBase, \ref TopicClassHierarchy - */ -template class ArrayBase - : public DenseBase -{ - public: -#ifndef EIGEN_PARSED_BY_DOXYGEN - /** The base class for a given storage type. */ - typedef ArrayBase StorageBaseType; - - typedef ArrayBase Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl; - - typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; - typedef typename internal::traits::Scalar Scalar; - typedef typename internal::packet_traits::type PacketScalar; - typedef typename NumTraits::Real RealScalar; - - typedef DenseBase Base; - using Base::operator*; - using Base::RowsAtCompileTime; - using Base::ColsAtCompileTime; - using Base::SizeAtCompileTime; - using Base::MaxRowsAtCompileTime; - using Base::MaxColsAtCompileTime; - using Base::MaxSizeAtCompileTime; - using Base::IsVectorAtCompileTime; - using Base::Flags; - using Base::CoeffReadCost; - - using Base::derived; - using Base::const_cast_derived; - using Base::rows; - using Base::cols; - using Base::size; - using Base::coeff; - using Base::coeffRef; - using Base::lazyAssign; - using Base::operator=; - using Base::operator+=; - using Base::operator-=; - using Base::operator*=; - using Base::operator/=; - - typedef typename Base::CoeffReturnType CoeffReturnType; - -#endif // not EIGEN_PARSED_BY_DOXYGEN - -#ifndef EIGEN_PARSED_BY_DOXYGEN - /** \internal the plain matrix type corresponding to this expression. Note that is not necessarily - * exactly the return type of eval(): in the case of plain matrices, the return type of eval() is a const - * reference to a matrix, not a matrix! It is however guaranteed that the return type of eval() is either - * PlainObject or const PlainObject&. - */ - typedef Array::Scalar, - internal::traits::RowsAtCompileTime, - internal::traits::ColsAtCompileTime, - AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), - internal::traits::MaxRowsAtCompileTime, - internal::traits::MaxColsAtCompileTime - > PlainObject; - - - /** \internal Represents a matrix with all coefficients equal to one another*/ - typedef CwiseNullaryOp,Derived> ConstantReturnType; -#endif // not EIGEN_PARSED_BY_DOXYGEN - -#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::ArrayBase -# include "../plugins/CommonCwiseUnaryOps.h" -# include "../plugins/MatrixCwiseUnaryOps.h" -# include "../plugins/ArrayCwiseUnaryOps.h" -# include "../plugins/CommonCwiseBinaryOps.h" -# include "../plugins/MatrixCwiseBinaryOps.h" -# include "../plugins/ArrayCwiseBinaryOps.h" -# ifdef EIGEN_ARRAYBASE_PLUGIN -# include EIGEN_ARRAYBASE_PLUGIN -# endif -#undef EIGEN_CURRENT_STORAGE_BASE_CLASS - - /** Special case of the template operator=, in order to prevent the compiler - * from generating a default operator= (issue hit with g++ 4.1) - */ - Derived& operator=(const ArrayBase& other) - { - return internal::assign_selector::run(derived(), other.derived()); - } - - Derived& operator+=(const Scalar& scalar) - { return *this = derived() + scalar; } - Derived& operator-=(const Scalar& scalar) - { return *this = derived() - scalar; } - - template - Derived& operator+=(const ArrayBase& other); - template - Derived& operator-=(const ArrayBase& other); - - template - Derived& operator*=(const ArrayBase& other); - - template - Derived& operator/=(const ArrayBase& other); - - public: - ArrayBase& array() { return *this; } - const ArrayBase& array() const { return *this; } - - /** \returns an \link Eigen::MatrixBase Matrix \endlink expression of this array - * \sa MatrixBase::array() */ - MatrixWrapper matrix() { return derived(); } - const MatrixWrapper matrix() const { return derived(); } - -// template -// inline void evalTo(Dest& dst) const { dst = matrix(); } - - protected: - ArrayBase() : Base() {} - - private: - explicit ArrayBase(Index); - ArrayBase(Index,Index); - template explicit ArrayBase(const ArrayBase&); - protected: - // mixing arrays and matrices is not legal - template Derived& operator+=(const MatrixBase& ) - {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} - // mixing arrays and matrices is not legal - template Derived& operator-=(const MatrixBase& ) - {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} -}; - -/** replaces \c *this by \c *this - \a other. - * - * \returns a reference to \c *this - */ -template -template -EIGEN_STRONG_INLINE Derived & -ArrayBase::operator-=(const ArrayBase &other) -{ - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); - return derived(); -} - -/** replaces \c *this by \c *this + \a other. - * - * \returns a reference to \c *this - */ -template -template -EIGEN_STRONG_INLINE Derived & -ArrayBase::operator+=(const ArrayBase& other) -{ - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); - return derived(); -} - -/** replaces \c *this by \c *this * \a other coefficient wise. - * - * \returns a reference to \c *this - */ -template -template -EIGEN_STRONG_INLINE Derived & -ArrayBase::operator*=(const ArrayBase& other) -{ - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); - return derived(); -} - -/** replaces \c *this by \c *this / \a other coefficient wise. - * - * \returns a reference to \c *this - */ -template -template -EIGEN_STRONG_INLINE Derived & -ArrayBase::operator/=(const ArrayBase& other) -{ - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); - return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_ARRAYBASE_H diff --git a/splinter/src/Core/ArrayWrapper.h b/splinter/src/Core/ArrayWrapper.h deleted file mode 100644 index b4641e2a01..0000000000 --- a/splinter/src/Core/ArrayWrapper.h +++ /dev/null @@ -1,264 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_ARRAYWRAPPER_H -#define EIGEN_ARRAYWRAPPER_H - -namespace Eigen { - -/** \class ArrayWrapper - * \ingroup Core_Module - * - * \brief Expression of a mathematical vector or matrix as an array object - * - * This class is the return type of MatrixBase::array(), and most of the time - * this is the only way it is use. - * - * \sa MatrixBase::array(), class MatrixWrapper - */ - -namespace internal { -template -struct traits > - : public traits::type > -{ - typedef ArrayXpr XprKind; - // Let's remove NestByRefBit - enum { - Flags0 = traits::type >::Flags, - Flags = Flags0 & ~NestByRefBit - }; -}; -} - -template -class ArrayWrapper : public ArrayBase > -{ - public: - typedef ArrayBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(ArrayWrapper) - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(ArrayWrapper) - - typedef typename internal::conditional< - internal::is_lvalue::value, - Scalar, - const Scalar - >::type ScalarWithConstIfNotLvalue; - - typedef typename internal::nested::type NestedExpressionType; - - inline ArrayWrapper(ExpressionType& matrix) : m_expression(matrix) {} - - inline Index rows() const { return m_expression.rows(); } - inline Index cols() const { return m_expression.cols(); } - inline Index outerStride() const { return m_expression.outerStride(); } - inline Index innerStride() const { return m_expression.innerStride(); } - - inline ScalarWithConstIfNotLvalue* data() { return m_expression.const_cast_derived().data(); } - inline const Scalar* data() const { return m_expression.data(); } - - inline CoeffReturnType coeff(Index rowId, Index colId) const - { - return m_expression.coeff(rowId, colId); - } - - inline Scalar& coeffRef(Index rowId, Index colId) - { - return m_expression.const_cast_derived().coeffRef(rowId, colId); - } - - inline const Scalar& coeffRef(Index rowId, Index colId) const - { - return m_expression.const_cast_derived().coeffRef(rowId, colId); - } - - inline CoeffReturnType coeff(Index index) const - { - return m_expression.coeff(index); - } - - inline Scalar& coeffRef(Index index) - { - return m_expression.const_cast_derived().coeffRef(index); - } - - inline const Scalar& coeffRef(Index index) const - { - return m_expression.const_cast_derived().coeffRef(index); - } - - template - inline const PacketScalar packet(Index rowId, Index colId) const - { - return m_expression.template packet(rowId, colId); - } - - template - inline void writePacket(Index rowId, Index colId, const PacketScalar& val) - { - m_expression.const_cast_derived().template writePacket(rowId, colId, val); - } - - template - inline const PacketScalar packet(Index index) const - { - return m_expression.template packet(index); - } - - template - inline void writePacket(Index index, const PacketScalar& val) - { - m_expression.const_cast_derived().template writePacket(index, val); - } - - template - inline void evalTo(Dest& dst) const { dst = m_expression; } - - const typename internal::remove_all::type& - nestedExpression() const - { - return m_expression; - } - - /** Forwards the resizing request to the nested expression - * \sa DenseBase::resize(Index) */ - void resize(Index newSize) { m_expression.const_cast_derived().resize(newSize); } - /** Forwards the resizing request to the nested expression - * \sa DenseBase::resize(Index,Index)*/ - void resize(Index nbRows, Index nbCols) { m_expression.const_cast_derived().resize(nbRows,nbCols); } - - protected: - NestedExpressionType m_expression; -}; - -/** \class MatrixWrapper - * \ingroup Core_Module - * - * \brief Expression of an array as a mathematical vector or matrix - * - * This class is the return type of ArrayBase::matrix(), and most of the time - * this is the only way it is use. - * - * \sa MatrixBase::matrix(), class ArrayWrapper - */ - -namespace internal { -template -struct traits > - : public traits::type > -{ - typedef MatrixXpr XprKind; - // Let's remove NestByRefBit - enum { - Flags0 = traits::type >::Flags, - Flags = Flags0 & ~NestByRefBit - }; -}; -} - -template -class MatrixWrapper : public MatrixBase > -{ - public: - typedef MatrixBase > Base; - EIGEN_DENSE_PUBLIC_INTERFACE(MatrixWrapper) - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(MatrixWrapper) - - typedef typename internal::conditional< - internal::is_lvalue::value, - Scalar, - const Scalar - >::type ScalarWithConstIfNotLvalue; - - typedef typename internal::nested::type NestedExpressionType; - - inline MatrixWrapper(ExpressionType& a_matrix) : m_expression(a_matrix) {} - - inline Index rows() const { return m_expression.rows(); } - inline Index cols() const { return m_expression.cols(); } - inline Index outerStride() const { return m_expression.outerStride(); } - inline Index innerStride() const { return m_expression.innerStride(); } - - inline ScalarWithConstIfNotLvalue* data() { return m_expression.const_cast_derived().data(); } - inline const Scalar* data() const { return m_expression.data(); } - - inline CoeffReturnType coeff(Index rowId, Index colId) const - { - return m_expression.coeff(rowId, colId); - } - - inline Scalar& coeffRef(Index rowId, Index colId) - { - return m_expression.const_cast_derived().coeffRef(rowId, colId); - } - - inline const Scalar& coeffRef(Index rowId, Index colId) const - { - return m_expression.derived().coeffRef(rowId, colId); - } - - inline CoeffReturnType coeff(Index index) const - { - return m_expression.coeff(index); - } - - inline Scalar& coeffRef(Index index) - { - return m_expression.const_cast_derived().coeffRef(index); - } - - inline const Scalar& coeffRef(Index index) const - { - return m_expression.const_cast_derived().coeffRef(index); - } - - template - inline const PacketScalar packet(Index rowId, Index colId) const - { - return m_expression.template packet(rowId, colId); - } - - template - inline void writePacket(Index rowId, Index colId, const PacketScalar& val) - { - m_expression.const_cast_derived().template writePacket(rowId, colId, val); - } - - template - inline const PacketScalar packet(Index index) const - { - return m_expression.template packet(index); - } - - template - inline void writePacket(Index index, const PacketScalar& val) - { - m_expression.const_cast_derived().template writePacket(index, val); - } - - const typename internal::remove_all::type& - nestedExpression() const - { - return m_expression; - } - - /** Forwards the resizing request to the nested expression - * \sa DenseBase::resize(Index) */ - void resize(Index newSize) { m_expression.const_cast_derived().resize(newSize); } - /** Forwards the resizing request to the nested expression - * \sa DenseBase::resize(Index,Index)*/ - void resize(Index nbRows, Index nbCols) { m_expression.const_cast_derived().resize(nbRows,nbCols); } - - protected: - NestedExpressionType m_expression; -}; - -} // end namespace Eigen - -#endif // EIGEN_ARRAYWRAPPER_H diff --git a/splinter/src/Core/Assign.h b/splinter/src/Core/Assign.h deleted file mode 100644 index f481731727..0000000000 --- a/splinter/src/Core/Assign.h +++ /dev/null @@ -1,590 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2007 Michael Olbrich -// Copyright (C) 2006-2010 Benoit Jacob -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_ASSIGN_H -#define EIGEN_ASSIGN_H - -namespace Eigen { - -namespace internal { - -/*************************************************************************** -* Part 1 : the logic deciding a strategy for traversal and unrolling * -***************************************************************************/ - -template -struct assign_traits -{ -public: - enum { - DstIsAligned = Derived::Flags & AlignedBit, - DstHasDirectAccess = Derived::Flags & DirectAccessBit, - SrcIsAligned = OtherDerived::Flags & AlignedBit, - JointAlignment = bool(DstIsAligned) && bool(SrcIsAligned) ? Aligned : Unaligned - }; - -private: - enum { - InnerSize = int(Derived::IsVectorAtCompileTime) ? int(Derived::SizeAtCompileTime) - : int(Derived::Flags)&RowMajorBit ? int(Derived::ColsAtCompileTime) - : int(Derived::RowsAtCompileTime), - InnerMaxSize = int(Derived::IsVectorAtCompileTime) ? int(Derived::MaxSizeAtCompileTime) - : int(Derived::Flags)&RowMajorBit ? int(Derived::MaxColsAtCompileTime) - : int(Derived::MaxRowsAtCompileTime), - MaxSizeAtCompileTime = Derived::SizeAtCompileTime, - PacketSize = packet_traits::size - }; - - enum { - StorageOrdersAgree = (int(Derived::IsRowMajor) == int(OtherDerived::IsRowMajor)), - MightVectorize = StorageOrdersAgree - && (int(Derived::Flags) & int(OtherDerived::Flags) & ActualPacketAccessBit), - MayInnerVectorize = MightVectorize && int(InnerSize)!=Dynamic && int(InnerSize)%int(PacketSize)==0 - && int(DstIsAligned) && int(SrcIsAligned), - MayLinearize = StorageOrdersAgree && (int(Derived::Flags) & int(OtherDerived::Flags) & LinearAccessBit), - MayLinearVectorize = MightVectorize && MayLinearize && DstHasDirectAccess - && (DstIsAligned || MaxSizeAtCompileTime == Dynamic), - /* If the destination isn't aligned, we have to do runtime checks and we don't unroll, - so it's only good for large enough sizes. */ - MaySliceVectorize = MightVectorize && DstHasDirectAccess - && (int(InnerMaxSize)==Dynamic || int(InnerMaxSize)>=3*PacketSize) - /* slice vectorization can be slow, so we only want it if the slices are big, which is - indicated by InnerMaxSize rather than InnerSize, think of the case of a dynamic block - in a fixed-size matrix */ - }; - -public: - enum { - Traversal = int(MayInnerVectorize) ? int(InnerVectorizedTraversal) - : int(MayLinearVectorize) ? int(LinearVectorizedTraversal) - : int(MaySliceVectorize) ? int(SliceVectorizedTraversal) - : int(MayLinearize) ? int(LinearTraversal) - : int(DefaultTraversal), - Vectorized = int(Traversal) == InnerVectorizedTraversal - || int(Traversal) == LinearVectorizedTraversal - || int(Traversal) == SliceVectorizedTraversal - }; - -private: - enum { - UnrollingLimit = EIGEN_UNROLLING_LIMIT * (Vectorized ? int(PacketSize) : 1), - MayUnrollCompletely = int(Derived::SizeAtCompileTime) != Dynamic - && int(OtherDerived::CoeffReadCost) != Dynamic - && int(Derived::SizeAtCompileTime) * int(OtherDerived::CoeffReadCost) <= int(UnrollingLimit), - MayUnrollInner = int(InnerSize) != Dynamic - && int(OtherDerived::CoeffReadCost) != Dynamic - && int(InnerSize) * int(OtherDerived::CoeffReadCost) <= int(UnrollingLimit) - }; - -public: - enum { - Unrolling = (int(Traversal) == int(InnerVectorizedTraversal) || int(Traversal) == int(DefaultTraversal)) - ? ( - int(MayUnrollCompletely) ? int(CompleteUnrolling) - : int(MayUnrollInner) ? int(InnerUnrolling) - : int(NoUnrolling) - ) - : int(Traversal) == int(LinearVectorizedTraversal) - ? ( bool(MayUnrollCompletely) && bool(DstIsAligned) ? int(CompleteUnrolling) : int(NoUnrolling) ) - : int(Traversal) == int(LinearTraversal) - ? ( bool(MayUnrollCompletely) ? int(CompleteUnrolling) : int(NoUnrolling) ) - : int(NoUnrolling) - }; - -#ifdef EIGEN_DEBUG_ASSIGN - static void debug() - { - EIGEN_DEBUG_VAR(DstIsAligned) - EIGEN_DEBUG_VAR(SrcIsAligned) - EIGEN_DEBUG_VAR(JointAlignment) - EIGEN_DEBUG_VAR(InnerSize) - EIGEN_DEBUG_VAR(InnerMaxSize) - EIGEN_DEBUG_VAR(PacketSize) - EIGEN_DEBUG_VAR(StorageOrdersAgree) - EIGEN_DEBUG_VAR(MightVectorize) - EIGEN_DEBUG_VAR(MayLinearize) - EIGEN_DEBUG_VAR(MayInnerVectorize) - EIGEN_DEBUG_VAR(MayLinearVectorize) - EIGEN_DEBUG_VAR(MaySliceVectorize) - EIGEN_DEBUG_VAR(Traversal) - EIGEN_DEBUG_VAR(UnrollingLimit) - EIGEN_DEBUG_VAR(MayUnrollCompletely) - EIGEN_DEBUG_VAR(MayUnrollInner) - EIGEN_DEBUG_VAR(Unrolling) - } -#endif -}; - -/*************************************************************************** -* Part 2 : meta-unrollers -***************************************************************************/ - -/************************ -*** Default traversal *** -************************/ - -template -struct assign_DefaultTraversal_CompleteUnrolling -{ - enum { - outer = Index / Derived1::InnerSizeAtCompileTime, - inner = Index % Derived1::InnerSizeAtCompileTime - }; - - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - dst.copyCoeffByOuterInner(outer, inner, src); - assign_DefaultTraversal_CompleteUnrolling::run(dst, src); - } -}; - -template -struct assign_DefaultTraversal_CompleteUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} -}; - -template -struct assign_DefaultTraversal_InnerUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src, typename Derived1::Index outer) - { - dst.copyCoeffByOuterInner(outer, Index, src); - assign_DefaultTraversal_InnerUnrolling::run(dst, src, outer); - } -}; - -template -struct assign_DefaultTraversal_InnerUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &, typename Derived1::Index) {} -}; - -/*********************** -*** Linear traversal *** -***********************/ - -template -struct assign_LinearTraversal_CompleteUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - dst.copyCoeff(Index, src); - assign_LinearTraversal_CompleteUnrolling::run(dst, src); - } -}; - -template -struct assign_LinearTraversal_CompleteUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} -}; - -/************************** -*** Inner vectorization *** -**************************/ - -template -struct assign_innervec_CompleteUnrolling -{ - enum { - outer = Index / Derived1::InnerSizeAtCompileTime, - inner = Index % Derived1::InnerSizeAtCompileTime, - JointAlignment = assign_traits::JointAlignment - }; - - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - dst.template copyPacketByOuterInner(outer, inner, src); - assign_innervec_CompleteUnrolling::size, Stop>::run(dst, src); - } -}; - -template -struct assign_innervec_CompleteUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} -}; - -template -struct assign_innervec_InnerUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src, typename Derived1::Index outer) - { - dst.template copyPacketByOuterInner(outer, Index, src); - assign_innervec_InnerUnrolling::size, Stop>::run(dst, src, outer); - } -}; - -template -struct assign_innervec_InnerUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &, typename Derived1::Index) {} -}; - -/*************************************************************************** -* Part 3 : implementation of all cases -***************************************************************************/ - -template::Traversal, - int Unrolling = assign_traits::Unrolling, - int Version = Specialized> -struct assign_impl; - -/************************ -*** Default traversal *** -************************/ - -template -struct assign_impl -{ - static inline void run(Derived1 &, const Derived2 &) { } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - const Index innerSize = dst.innerSize(); - const Index outerSize = dst.outerSize(); - for(Index outer = 0; outer < outerSize; ++outer) - for(Index inner = 0; inner < innerSize; ++inner) - dst.copyCoeffByOuterInner(outer, inner, src); - } -}; - -template -struct assign_impl -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - assign_DefaultTraversal_CompleteUnrolling - ::run(dst, src); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - const Index outerSize = dst.outerSize(); - for(Index outer = 0; outer < outerSize; ++outer) - assign_DefaultTraversal_InnerUnrolling - ::run(dst, src, outer); - } -}; - -/*********************** -*** Linear traversal *** -***********************/ - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - const Index size = dst.size(); - for(Index i = 0; i < size; ++i) - dst.copyCoeff(i, src); - } -}; - -template -struct assign_impl -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - assign_LinearTraversal_CompleteUnrolling - ::run(dst, src); - } -}; - -/************************** -*** Inner vectorization *** -**************************/ - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - const Index innerSize = dst.innerSize(); - const Index outerSize = dst.outerSize(); - const Index packetSize = packet_traits::size; - for(Index outer = 0; outer < outerSize; ++outer) - for(Index inner = 0; inner < innerSize; inner+=packetSize) - dst.template copyPacketByOuterInner(outer, inner, src); - } -}; - -template -struct assign_impl -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - assign_innervec_CompleteUnrolling - ::run(dst, src); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - const Index outerSize = dst.outerSize(); - for(Index outer = 0; outer < outerSize; ++outer) - assign_innervec_InnerUnrolling - ::run(dst, src, outer); - } -}; - -/*************************** -*** Linear vectorization *** -***************************/ - -template -struct unaligned_assign_impl -{ - template - static EIGEN_STRONG_INLINE void run(const Derived&, OtherDerived&, typename Derived::Index, typename Derived::Index) {} -}; - -template <> -struct unaligned_assign_impl -{ - // MSVC must not inline this functions. If it does, it fails to optimize the - // packet access path. -#ifdef _MSC_VER - template - static EIGEN_DONT_INLINE void run(const Derived& src, OtherDerived& dst, typename Derived::Index start, typename Derived::Index end) -#else - template - static EIGEN_STRONG_INLINE void run(const Derived& src, OtherDerived& dst, typename Derived::Index start, typename Derived::Index end) -#endif - { - for (typename Derived::Index index = start; index < end; ++index) - dst.copyCoeff(index, src); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - const Index size = dst.size(); - typedef packet_traits PacketTraits; - enum { - packetSize = PacketTraits::size, - dstAlignment = PacketTraits::AlignedOnScalar ? Aligned : int(assign_traits::DstIsAligned) , - srcAlignment = assign_traits::JointAlignment - }; - const Index alignedStart = assign_traits::DstIsAligned ? 0 - : internal::first_aligned(&dst.coeffRef(0), size); - const Index alignedEnd = alignedStart + ((size-alignedStart)/packetSize)*packetSize; - - unaligned_assign_impl::DstIsAligned!=0>::run(src,dst,0,alignedStart); - - for(Index index = alignedStart; index < alignedEnd; index += packetSize) - { - dst.template copyPacket(index, src); - } - - unaligned_assign_impl<>::run(src,dst,alignedEnd,size); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - enum { size = Derived1::SizeAtCompileTime, - packetSize = packet_traits::size, - alignedSize = (size/packetSize)*packetSize }; - - assign_innervec_CompleteUnrolling::run(dst, src); - assign_DefaultTraversal_CompleteUnrolling::run(dst, src); - } -}; - -/************************** -*** Slice vectorization *** -***************************/ - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - typedef typename Derived1::Scalar Scalar; - typedef packet_traits PacketTraits; - enum { - packetSize = PacketTraits::size, - alignable = PacketTraits::AlignedOnScalar, - dstIsAligned = assign_traits::DstIsAligned, - dstAlignment = alignable ? Aligned : int(dstIsAligned), - srcAlignment = assign_traits::JointAlignment - }; - const Scalar *dst_ptr = &dst.coeffRef(0,0); - if((!bool(dstIsAligned)) && (size_t(dst_ptr) % sizeof(Scalar))>0) - { - // the pointer is not aligend-on scalar, so alignment is not possible - return assign_impl::run(dst, src); - } - const Index packetAlignedMask = packetSize - 1; - const Index innerSize = dst.innerSize(); - const Index outerSize = dst.outerSize(); - const Index alignedStep = alignable ? (packetSize - dst.outerStride() % packetSize) & packetAlignedMask : 0; - Index alignedStart = ((!alignable) || bool(dstIsAligned)) ? 0 : internal::first_aligned(dst_ptr, innerSize); - - for(Index outer = 0; outer < outerSize; ++outer) - { - const Index alignedEnd = alignedStart + ((innerSize-alignedStart) & ~packetAlignedMask); - // do the non-vectorizable part of the assignment - for(Index inner = 0; inner(outer, inner, src); - - // do the non-vectorizable part of the assignment - for(Index inner = alignedEnd; inner((alignedStart+alignedStep)%packetSize, innerSize); - } - } -}; - -} // end namespace internal - -/*************************************************************************** -* Part 4 : implementation of DenseBase methods -***************************************************************************/ - -template -template -EIGEN_STRONG_INLINE Derived& DenseBase - ::lazyAssign(const DenseBase& other) -{ - enum{ - SameType = internal::is_same::value - }; - - EIGEN_STATIC_ASSERT_LVALUE(Derived) - EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived) - EIGEN_STATIC_ASSERT(SameType,YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - -#ifdef EIGEN_DEBUG_ASSIGN - internal::assign_traits::debug(); -#endif - eigen_assert(rows() == other.rows() && cols() == other.cols()); - internal::assign_impl::Traversal) - : int(InvalidTraversal)>::run(derived(),other.derived()); -#ifndef EIGEN_NO_DEBUG - checkTransposeAliasing(other.derived()); -#endif - return derived(); -} - -namespace internal { - -template::Flags) & EvalBeforeAssigningBit) != 0, - bool NeedToTranspose = ((int(Derived::RowsAtCompileTime) == 1 && int(OtherDerived::ColsAtCompileTime) == 1) - | // FIXME | instead of || to please GCC 4.4.0 stupid warning "suggest parentheses around &&". - // revert to || as soon as not needed anymore. - (int(Derived::ColsAtCompileTime) == 1 && int(OtherDerived::RowsAtCompileTime) == 1)) - && int(Derived::SizeAtCompileTime) != 1> -struct assign_selector; - -template -struct assign_selector { - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.derived()); } - template - static EIGEN_STRONG_INLINE Derived& evalTo(ActualDerived& dst, const ActualOtherDerived& other) { other.evalTo(dst); return dst; } -}; -template -struct assign_selector { - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.eval()); } -}; -template -struct assign_selector { - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose()); } - template - static EIGEN_STRONG_INLINE Derived& evalTo(ActualDerived& dst, const ActualOtherDerived& other) { Transpose dstTrans(dst); other.evalTo(dstTrans); return dst; } -}; -template -struct assign_selector { - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose().eval()); } -}; - -} // end namespace internal - -template -template -EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) -{ - return internal::assign_selector::run(derived(), other.derived()); -} - -template -EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) -{ - return internal::assign_selector::run(derived(), other.derived()); -} - -template -EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const MatrixBase& other) -{ - return internal::assign_selector::run(derived(), other.derived()); -} - -template -template -EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const DenseBase& other) -{ - return internal::assign_selector::run(derived(), other.derived()); -} - -template -template -EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const EigenBase& other) -{ - return internal::assign_selector::evalTo(derived(), other.derived()); -} - -template -template -EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const ReturnByValue& other) -{ - return internal::assign_selector::evalTo(derived(), other.derived()); -} - -} // end namespace Eigen - -#endif // EIGEN_ASSIGN_H diff --git a/splinter/src/Core/Assign_MKL.h b/splinter/src/Core/Assign_MKL.h deleted file mode 100644 index 7772951b91..0000000000 --- a/splinter/src/Core/Assign_MKL.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - Copyright (c) 2011, Intel Corporation. All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of Intel Corporation nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - ******************************************************************************** - * Content : Eigen bindings to Intel(R) MKL - * MKL VML support for coefficient-wise unary Eigen expressions like a=b.sin() - ******************************************************************************** -*/ - -#ifndef EIGEN_ASSIGN_VML_H -#define EIGEN_ASSIGN_VML_H - -namespace Eigen { - -namespace internal { - -template struct vml_call -{ enum { IsSupported = 0 }; }; - -template -class vml_assign_traits -{ - private: - enum { - DstHasDirectAccess = Dst::Flags & DirectAccessBit, - SrcHasDirectAccess = Src::Flags & DirectAccessBit, - - StorageOrdersAgree = (int(Dst::IsRowMajor) == int(Src::IsRowMajor)), - InnerSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::SizeAtCompileTime) - : int(Dst::Flags)&RowMajorBit ? int(Dst::ColsAtCompileTime) - : int(Dst::RowsAtCompileTime), - InnerMaxSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::MaxSizeAtCompileTime) - : int(Dst::Flags)&RowMajorBit ? int(Dst::MaxColsAtCompileTime) - : int(Dst::MaxRowsAtCompileTime), - MaxSizeAtCompileTime = Dst::SizeAtCompileTime, - - MightEnableVml = vml_call::IsSupported && StorageOrdersAgree && DstHasDirectAccess && SrcHasDirectAccess - && Src::InnerStrideAtCompileTime==1 && Dst::InnerStrideAtCompileTime==1, - MightLinearize = MightEnableVml && (int(Dst::Flags) & int(Src::Flags) & LinearAccessBit), - VmlSize = MightLinearize ? MaxSizeAtCompileTime : InnerMaxSize, - LargeEnough = VmlSize==Dynamic || VmlSize>=EIGEN_MKL_VML_THRESHOLD, - MayEnableVml = MightEnableVml && LargeEnough, - MayLinearize = MayEnableVml && MightLinearize - }; - public: - enum { - Traversal = MayLinearize ? LinearVectorizedTraversal - : MayEnableVml ? InnerVectorizedTraversal - : DefaultTraversal - }; -}; - -template::Traversal > -struct vml_assign_impl - : assign_impl,Traversal,Unrolling,BuiltIn> -{ -}; - -template -struct vml_assign_impl -{ - typedef typename Derived1::Scalar Scalar; - typedef typename Derived1::Index Index; - static inline void run(Derived1& dst, const CwiseUnaryOp& src) - { - // in case we want to (or have to) skip VML at runtime we can call: - // assign_impl,Traversal,Unrolling,BuiltIn>::run(dst,src); - const Index innerSize = dst.innerSize(); - const Index outerSize = dst.outerSize(); - for(Index outer = 0; outer < outerSize; ++outer) { - const Scalar *src_ptr = src.IsRowMajor ? &(src.nestedExpression().coeffRef(outer,0)) : - &(src.nestedExpression().coeffRef(0, outer)); - Scalar *dst_ptr = dst.IsRowMajor ? &(dst.coeffRef(outer,0)) : &(dst.coeffRef(0, outer)); - vml_call::run(src.functor(), innerSize, src_ptr, dst_ptr ); - } - } -}; - -template -struct vml_assign_impl -{ - static inline void run(Derived1& dst, const CwiseUnaryOp& src) - { - // in case we want to (or have to) skip VML at runtime we can call: - // assign_impl,Traversal,Unrolling,BuiltIn>::run(dst,src); - vml_call::run(src.functor(), dst.size(), src.nestedExpression().data(), dst.data() ); - } -}; - -// Macroses - -#define EIGEN_MKL_VML_SPECIALIZE_ASSIGN(TRAVERSAL,UNROLLING) \ - template \ - struct assign_impl, TRAVERSAL, UNROLLING, Specialized> { \ - static inline void run(Derived1 &dst, const Eigen::CwiseUnaryOp &src) { \ - vml_assign_impl::run(dst, src); \ - } \ - }; - -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(DefaultTraversal,NoUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(DefaultTraversal,CompleteUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(DefaultTraversal,InnerUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearTraversal,NoUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearTraversal,CompleteUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(InnerVectorizedTraversal,NoUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(InnerVectorizedTraversal,CompleteUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(InnerVectorizedTraversal,InnerUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearVectorizedTraversal,CompleteUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearVectorizedTraversal,NoUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(SliceVectorizedTraversal,NoUnrolling) - - -#if !defined (EIGEN_FAST_MATH) || (EIGEN_FAST_MATH != 1) -#define EIGEN_MKL_VML_MODE VML_HA -#else -#define EIGEN_MKL_VML_MODE VML_LA -#endif - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE) \ - template<> struct vml_call< scalar_##EIGENOP##_op > { \ - enum { IsSupported = 1 }; \ - static inline void run( const scalar_##EIGENOP##_op& /*func*/, \ - int size, const EIGENTYPE* src, EIGENTYPE* dst) { \ - VMLOP(size, (const VMLTYPE*)src, (VMLTYPE*)dst); \ - } \ - }; - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE) \ - template<> struct vml_call< scalar_##EIGENOP##_op > { \ - enum { IsSupported = 1 }; \ - static inline void run( const scalar_##EIGENOP##_op& /*func*/, \ - int size, const EIGENTYPE* src, EIGENTYPE* dst) { \ - MKL_INT64 vmlMode = EIGEN_MKL_VML_MODE; \ - VMLOP(size, (const VMLTYPE*)src, (VMLTYPE*)dst, vmlMode); \ - } \ - }; - -#define EIGEN_MKL_VML_DECLARE_POW_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE) \ - template<> struct vml_call< scalar_##EIGENOP##_op > { \ - enum { IsSupported = 1 }; \ - static inline void run( const scalar_##EIGENOP##_op& func, \ - int size, const EIGENTYPE* src, EIGENTYPE* dst) { \ - EIGENTYPE exponent = func.m_exponent; \ - MKL_INT64 vmlMode = EIGEN_MKL_VML_MODE; \ - VMLOP(&size, (const VMLTYPE*)src, (const VMLTYPE*)&exponent, \ - (VMLTYPE*)dst, &vmlMode); \ - } \ - }; - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vs##VMLOP, float, float) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vd##VMLOP, double, double) - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vc##VMLOP, scomplex, MKL_Complex8) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vz##VMLOP, dcomplex, MKL_Complex16) - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX(EIGENOP, VMLOP) - - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL_LA(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vms##VMLOP, float, float) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vmd##VMLOP, double, double) - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX_LA(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vmc##VMLOP, scomplex, MKL_Complex8) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vmz##VMLOP, dcomplex, MKL_Complex16) - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL_LA(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX_LA(EIGENOP, VMLOP) - - -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(sin, Sin) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(asin, Asin) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(cos, Cos) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(acos, Acos) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(tan, Tan) -//EIGEN_MKL_VML_DECLARE_UNARY_CALLS(abs, Abs) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(exp, Exp) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(log, Ln) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(sqrt, Sqrt) - -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(square, Sqr) - -// The vm*powx functions are not avaibale in the windows version of MKL. -#ifndef _WIN32 -EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmspowx_, float, float) -EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmdpowx_, double, double) -EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmcpowx_, scomplex, MKL_Complex8) -EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmzpowx_, dcomplex, MKL_Complex16) -#endif - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_ASSIGN_VML_H diff --git a/splinter/src/Core/BandMatrix.h b/splinter/src/Core/BandMatrix.h deleted file mode 100644 index ffd7fe8b30..0000000000 --- a/splinter/src/Core/BandMatrix.h +++ /dev/null @@ -1,334 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_BANDMATRIX_H -#define EIGEN_BANDMATRIX_H - -namespace Eigen { - -namespace internal { - -template -class BandMatrixBase : public EigenBase -{ - public: - - enum { - Flags = internal::traits::Flags, - CoeffReadCost = internal::traits::CoeffReadCost, - RowsAtCompileTime = internal::traits::RowsAtCompileTime, - ColsAtCompileTime = internal::traits::ColsAtCompileTime, - MaxRowsAtCompileTime = internal::traits::MaxRowsAtCompileTime, - MaxColsAtCompileTime = internal::traits::MaxColsAtCompileTime, - Supers = internal::traits::Supers, - Subs = internal::traits::Subs, - Options = internal::traits::Options - }; - typedef typename internal::traits::Scalar Scalar; - typedef Matrix DenseMatrixType; - typedef typename DenseMatrixType::Index Index; - typedef typename internal::traits::CoefficientsType CoefficientsType; - typedef EigenBase Base; - - protected: - enum { - DataRowsAtCompileTime = ((Supers!=Dynamic) && (Subs!=Dynamic)) - ? 1 + Supers + Subs - : Dynamic, - SizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_DYNAMIC(RowsAtCompileTime,ColsAtCompileTime) - }; - - public: - - using Base::derived; - using Base::rows; - using Base::cols; - - /** \returns the number of super diagonals */ - inline Index supers() const { return derived().supers(); } - - /** \returns the number of sub diagonals */ - inline Index subs() const { return derived().subs(); } - - /** \returns an expression of the underlying coefficient matrix */ - inline const CoefficientsType& coeffs() const { return derived().coeffs(); } - - /** \returns an expression of the underlying coefficient matrix */ - inline CoefficientsType& coeffs() { return derived().coeffs(); } - - /** \returns a vector expression of the \a i -th column, - * only the meaningful part is returned. - * \warning the internal storage must be column major. */ - inline Block col(Index i) - { - EIGEN_STATIC_ASSERT((Options&RowMajor)==0,THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES); - Index start = 0; - Index len = coeffs().rows(); - if (i<=supers()) - { - start = supers()-i; - len = (std::min)(rows(),std::max(0,coeffs().rows() - (supers()-i))); - } - else if (i>=rows()-subs()) - len = std::max(0,coeffs().rows() - (i + 1 - rows() + subs())); - return Block(coeffs(), start, i, len, 1); - } - - /** \returns a vector expression of the main diagonal */ - inline Block diagonal() - { return Block(coeffs(),supers(),0,1,(std::min)(rows(),cols())); } - - /** \returns a vector expression of the main diagonal (const version) */ - inline const Block diagonal() const - { return Block(coeffs(),supers(),0,1,(std::min)(rows(),cols())); } - - template struct DiagonalIntReturnType { - enum { - ReturnOpposite = (Options&SelfAdjoint) && (((Index)>0 && Supers==0) || ((Index)<0 && Subs==0)), - Conjugate = ReturnOpposite && NumTraits::IsComplex, - ActualIndex = ReturnOpposite ? -Index : Index, - DiagonalSize = (RowsAtCompileTime==Dynamic || ColsAtCompileTime==Dynamic) - ? Dynamic - : (ActualIndex<0 - ? EIGEN_SIZE_MIN_PREFER_DYNAMIC(ColsAtCompileTime, RowsAtCompileTime + ActualIndex) - : EIGEN_SIZE_MIN_PREFER_DYNAMIC(RowsAtCompileTime, ColsAtCompileTime - ActualIndex)) - }; - typedef Block BuildType; - typedef typename internal::conditional,BuildType >, - BuildType>::type Type; - }; - - /** \returns a vector expression of the \a N -th sub or super diagonal */ - template inline typename DiagonalIntReturnType::Type diagonal() - { - return typename DiagonalIntReturnType::BuildType(coeffs(), supers()-N, (std::max)(0,N), 1, diagonalLength(N)); - } - - /** \returns a vector expression of the \a N -th sub or super diagonal */ - template inline const typename DiagonalIntReturnType::Type diagonal() const - { - return typename DiagonalIntReturnType::BuildType(coeffs(), supers()-N, (std::max)(0,N), 1, diagonalLength(N)); - } - - /** \returns a vector expression of the \a i -th sub or super diagonal */ - inline Block diagonal(Index i) - { - eigen_assert((i<0 && -i<=subs()) || (i>=0 && i<=supers())); - return Block(coeffs(), supers()-i, std::max(0,i), 1, diagonalLength(i)); - } - - /** \returns a vector expression of the \a i -th sub or super diagonal */ - inline const Block diagonal(Index i) const - { - eigen_assert((i<0 && -i<=subs()) || (i>=0 && i<=supers())); - return Block(coeffs(), supers()-i, std::max(0,i), 1, diagonalLength(i)); - } - - template inline void evalTo(Dest& dst) const - { - dst.resize(rows(),cols()); - dst.setZero(); - dst.diagonal() = diagonal(); - for (Index i=1; i<=supers();++i) - dst.diagonal(i) = diagonal(i); - for (Index i=1; i<=subs();++i) - dst.diagonal(-i) = diagonal(-i); - } - - DenseMatrixType toDenseMatrix() const - { - DenseMatrixType res(rows(),cols()); - evalTo(res); - return res; - } - - protected: - - inline Index diagonalLength(Index i) const - { return i<0 ? (std::min)(cols(),rows()+i) : (std::min)(rows(),cols()-i); } -}; - -/** - * \class BandMatrix - * \ingroup Core_Module - * - * \brief Represents a rectangular matrix with a banded storage - * - * \param _Scalar Numeric type, i.e. float, double, int - * \param Rows Number of rows, or \b Dynamic - * \param Cols Number of columns, or \b Dynamic - * \param Supers Number of super diagonal - * \param Subs Number of sub diagonal - * \param _Options A combination of either \b #RowMajor or \b #ColMajor, and of \b #SelfAdjoint - * The former controls \ref TopicStorageOrders "storage order", and defaults to - * column-major. The latter controls whether the matrix represents a selfadjoint - * matrix in which case either Supers of Subs have to be null. - * - * \sa class TridiagonalMatrix - */ - -template -struct traits > -{ - typedef _Scalar Scalar; - typedef Dense StorageKind; - typedef DenseIndex Index; - enum { - CoeffReadCost = NumTraits::ReadCost, - RowsAtCompileTime = _Rows, - ColsAtCompileTime = _Cols, - MaxRowsAtCompileTime = _Rows, - MaxColsAtCompileTime = _Cols, - Flags = LvalueBit, - Supers = _Supers, - Subs = _Subs, - Options = _Options, - DataRowsAtCompileTime = ((Supers!=Dynamic) && (Subs!=Dynamic)) ? 1 + Supers + Subs : Dynamic - }; - typedef Matrix CoefficientsType; -}; - -template -class BandMatrix : public BandMatrixBase > -{ - public: - - typedef typename internal::traits::Scalar Scalar; - typedef typename internal::traits::Index Index; - typedef typename internal::traits::CoefficientsType CoefficientsType; - - inline BandMatrix(Index rows=Rows, Index cols=Cols, Index supers=Supers, Index subs=Subs) - : m_coeffs(1+supers+subs,cols), - m_rows(rows), m_supers(supers), m_subs(subs) - { - } - - /** \returns the number of columns */ - inline Index rows() const { return m_rows.value(); } - - /** \returns the number of rows */ - inline Index cols() const { return m_coeffs.cols(); } - - /** \returns the number of super diagonals */ - inline Index supers() const { return m_supers.value(); } - - /** \returns the number of sub diagonals */ - inline Index subs() const { return m_subs.value(); } - - inline const CoefficientsType& coeffs() const { return m_coeffs; } - inline CoefficientsType& coeffs() { return m_coeffs; } - - protected: - - CoefficientsType m_coeffs; - internal::variable_if_dynamic m_rows; - internal::variable_if_dynamic m_supers; - internal::variable_if_dynamic m_subs; -}; - -template -class BandMatrixWrapper; - -template -struct traits > -{ - typedef typename _CoefficientsType::Scalar Scalar; - typedef typename _CoefficientsType::StorageKind StorageKind; - typedef typename _CoefficientsType::Index Index; - enum { - CoeffReadCost = internal::traits<_CoefficientsType>::CoeffReadCost, - RowsAtCompileTime = _Rows, - ColsAtCompileTime = _Cols, - MaxRowsAtCompileTime = _Rows, - MaxColsAtCompileTime = _Cols, - Flags = LvalueBit, - Supers = _Supers, - Subs = _Subs, - Options = _Options, - DataRowsAtCompileTime = ((Supers!=Dynamic) && (Subs!=Dynamic)) ? 1 + Supers + Subs : Dynamic - }; - typedef _CoefficientsType CoefficientsType; -}; - -template -class BandMatrixWrapper : public BandMatrixBase > -{ - public: - - typedef typename internal::traits::Scalar Scalar; - typedef typename internal::traits::CoefficientsType CoefficientsType; - typedef typename internal::traits::Index Index; - - inline BandMatrixWrapper(const CoefficientsType& coeffs, Index rows=_Rows, Index cols=_Cols, Index supers=_Supers, Index subs=_Subs) - : m_coeffs(coeffs), - m_rows(rows), m_supers(supers), m_subs(subs) - { - EIGEN_UNUSED_VARIABLE(cols); - //internal::assert(coeffs.cols()==cols() && (supers()+subs()+1)==coeffs.rows()); - } - - /** \returns the number of columns */ - inline Index rows() const { return m_rows.value(); } - - /** \returns the number of rows */ - inline Index cols() const { return m_coeffs.cols(); } - - /** \returns the number of super diagonals */ - inline Index supers() const { return m_supers.value(); } - - /** \returns the number of sub diagonals */ - inline Index subs() const { return m_subs.value(); } - - inline const CoefficientsType& coeffs() const { return m_coeffs; } - - protected: - - const CoefficientsType& m_coeffs; - internal::variable_if_dynamic m_rows; - internal::variable_if_dynamic m_supers; - internal::variable_if_dynamic m_subs; -}; - -/** - * \class TridiagonalMatrix - * \ingroup Core_Module - * - * \brief Represents a tridiagonal matrix with a compact banded storage - * - * \param _Scalar Numeric type, i.e. float, double, int - * \param Size Number of rows and cols, or \b Dynamic - * \param _Options Can be 0 or \b SelfAdjoint - * - * \sa class BandMatrix - */ -template -class TridiagonalMatrix : public BandMatrix -{ - typedef BandMatrix Base; - typedef typename Base::Index Index; - public: - TridiagonalMatrix(Index size = Size) : Base(size,size,Options&SelfAdjoint?0:1,1) {} - - inline typename Base::template DiagonalIntReturnType<1>::Type super() - { return Base::template diagonal<1>(); } - inline const typename Base::template DiagonalIntReturnType<1>::Type super() const - { return Base::template diagonal<1>(); } - inline typename Base::template DiagonalIntReturnType<-1>::Type sub() - { return Base::template diagonal<-1>(); } - inline const typename Base::template DiagonalIntReturnType<-1>::Type sub() const - { return Base::template diagonal<-1>(); } - protected: -}; - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_BANDMATRIX_H diff --git a/splinter/src/Core/Block.h b/splinter/src/Core/Block.h deleted file mode 100644 index 8278944432..0000000000 --- a/splinter/src/Core/Block.h +++ /dev/null @@ -1,406 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2006-2010 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_BLOCK_H -#define EIGEN_BLOCK_H - -namespace Eigen { - -/** \class Block - * \ingroup Core_Module - * - * \brief Expression of a fixed-size or dynamic-size block - * - * \param XprType the type of the expression in which we are taking a block - * \param BlockRows the number of rows of the block we are taking at compile time (optional) - * \param BlockCols the number of columns of the block we are taking at compile time (optional) - * - * This class represents an expression of either a fixed-size or dynamic-size block. It is the return - * type of DenseBase::block(Index,Index,Index,Index) and DenseBase::block(Index,Index) and - * most of the time this is the only way it is used. - * - * However, if you want to directly maniputate block expressions, - * for instance if you want to write a function returning such an expression, you - * will need to use this class. - * - * Here is an example illustrating the dynamic case: - * \include class_Block.cpp - * Output: \verbinclude class_Block.out - * - * \note Even though this expression has dynamic size, in the case where \a XprType - * has fixed size, this expression inherits a fixed maximal size which means that evaluating - * it does not cause a dynamic memory allocation. - * - * Here is an example illustrating the fixed-size case: - * \include class_FixedBlock.cpp - * Output: \verbinclude class_FixedBlock.out - * - * \sa DenseBase::block(Index,Index,Index,Index), DenseBase::block(Index,Index), class VectorBlock - */ - -namespace internal { -template -struct traits > : traits -{ - typedef typename traits::Scalar Scalar; - typedef typename traits::StorageKind StorageKind; - typedef typename traits::XprKind XprKind; - typedef typename nested::type XprTypeNested; - typedef typename remove_reference::type _XprTypeNested; - enum{ - MatrixRows = traits::RowsAtCompileTime, - MatrixCols = traits::ColsAtCompileTime, - RowsAtCompileTime = MatrixRows == 0 ? 0 : BlockRows, - ColsAtCompileTime = MatrixCols == 0 ? 0 : BlockCols, - MaxRowsAtCompileTime = BlockRows==0 ? 0 - : RowsAtCompileTime != Dynamic ? int(RowsAtCompileTime) - : int(traits::MaxRowsAtCompileTime), - MaxColsAtCompileTime = BlockCols==0 ? 0 - : ColsAtCompileTime != Dynamic ? int(ColsAtCompileTime) - : int(traits::MaxColsAtCompileTime), - XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0, - IsDense = is_same::value, - IsRowMajor = (IsDense&&MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 - : (IsDense&&MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 - : XprTypeIsRowMajor, - HasSameStorageOrderAsXprType = (IsRowMajor == XprTypeIsRowMajor), - InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime), - InnerStrideAtCompileTime = HasSameStorageOrderAsXprType - ? int(inner_stride_at_compile_time::ret) - : int(outer_stride_at_compile_time::ret), - OuterStrideAtCompileTime = HasSameStorageOrderAsXprType - ? int(outer_stride_at_compile_time::ret) - : int(inner_stride_at_compile_time::ret), - MaskPacketAccessBit = (InnerSize == Dynamic || (InnerSize % packet_traits::size) == 0) - && (InnerStrideAtCompileTime == 1) - ? PacketAccessBit : 0, - MaskAlignedBit = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % 16) == 0)) ? AlignedBit : 0, - FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1 || (InnerPanel && (traits::Flags&LinearAccessBit))) ? LinearAccessBit : 0, - FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, - FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, - Flags0 = traits::Flags & ( (HereditaryBits & ~RowMajorBit) | - DirectAccessBit | - MaskPacketAccessBit | - MaskAlignedBit), - Flags = Flags0 | FlagsLinearAccessBit | FlagsLvalueBit | FlagsRowMajorBit - }; -}; - -template::ret> class BlockImpl_dense; - -} // end namespace internal - -template class BlockImpl; - -template class Block - : public BlockImpl::StorageKind> -{ - typedef BlockImpl::StorageKind> Impl; - public: - //typedef typename Impl::Base Base; - typedef Impl Base; - EIGEN_GENERIC_PUBLIC_INTERFACE(Block) - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Block) - - /** Column or Row constructor - */ - inline Block(XprType& xpr, Index i) : Impl(xpr,i) - { - eigen_assert( (i>=0) && ( - ((BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) && i= 0 && BlockRows >= 1 && a_startRow + BlockRows <= xpr.rows() - && a_startCol >= 0 && BlockCols >= 1 && a_startCol + BlockCols <= xpr.cols()); - } - - /** Dynamic-size constructor - */ - inline Block(XprType& xpr, - Index a_startRow, Index a_startCol, - Index blockRows, Index blockCols) - : Impl(xpr, a_startRow, a_startCol, blockRows, blockCols) - { - eigen_assert((RowsAtCompileTime==Dynamic || RowsAtCompileTime==blockRows) - && (ColsAtCompileTime==Dynamic || ColsAtCompileTime==blockCols)); - eigen_assert(a_startRow >= 0 && blockRows >= 0 && a_startRow <= xpr.rows() - blockRows - && a_startCol >= 0 && blockCols >= 0 && a_startCol <= xpr.cols() - blockCols); - } -}; - -// The generic default implementation for dense block simplu forward to the internal::BlockImpl_dense -// that must be specialized for direct and non-direct access... -template -class BlockImpl - : public internal::BlockImpl_dense -{ - typedef internal::BlockImpl_dense Impl; - typedef typename XprType::Index Index; - public: - typedef Impl Base; - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl) - inline BlockImpl(XprType& xpr, Index i) : Impl(xpr,i) {} - inline BlockImpl(XprType& xpr, Index a_startRow, Index a_startCol) : Impl(xpr, a_startRow, a_startCol) {} - inline BlockImpl(XprType& xpr, Index a_startRow, Index a_startCol, Index blockRows, Index blockCols) - : Impl(xpr, a_startRow, a_startCol, blockRows, blockCols) {} -}; - -namespace internal { - -/** \internal Internal implementation of dense Blocks in the general case. */ -template class BlockImpl_dense - : public internal::dense_xpr_base >::type -{ - typedef Block BlockType; - public: - - typedef typename internal::dense_xpr_base::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(BlockType) - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl_dense) - - class InnerIterator; - - /** Column or Row constructor - */ - inline BlockImpl_dense(XprType& xpr, Index i) - : m_xpr(xpr), - // It is a row if and only if BlockRows==1 and BlockCols==XprType::ColsAtCompileTime, - // and it is a column if and only if BlockRows==XprType::RowsAtCompileTime and BlockCols==1, - // all other cases are invalid. - // The case a 1x1 matrix seems ambiguous, but the result is the same anyway. - m_startRow( (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0), - m_startCol( (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0), - m_blockRows(BlockRows==1 ? 1 : xpr.rows()), - m_blockCols(BlockCols==1 ? 1 : xpr.cols()) - {} - - /** Fixed-size constructor - */ - inline BlockImpl_dense(XprType& xpr, Index a_startRow, Index a_startCol) - : m_xpr(xpr), m_startRow(a_startRow), m_startCol(a_startCol), - m_blockRows(BlockRows), m_blockCols(BlockCols) - {} - - /** Dynamic-size constructor - */ - inline BlockImpl_dense(XprType& xpr, - Index a_startRow, Index a_startCol, - Index blockRows, Index blockCols) - : m_xpr(xpr), m_startRow(a_startRow), m_startCol(a_startCol), - m_blockRows(blockRows), m_blockCols(blockCols) - {} - - inline Index rows() const { return m_blockRows.value(); } - inline Index cols() const { return m_blockCols.value(); } - - inline Scalar& coeffRef(Index rowId, Index colId) - { - EIGEN_STATIC_ASSERT_LVALUE(XprType) - return m_xpr.const_cast_derived() - .coeffRef(rowId + m_startRow.value(), colId + m_startCol.value()); - } - - inline const Scalar& coeffRef(Index rowId, Index colId) const - { - return m_xpr.derived() - .coeffRef(rowId + m_startRow.value(), colId + m_startCol.value()); - } - - EIGEN_STRONG_INLINE const CoeffReturnType coeff(Index rowId, Index colId) const - { - return m_xpr.coeff(rowId + m_startRow.value(), colId + m_startCol.value()); - } - - inline Scalar& coeffRef(Index index) - { - EIGEN_STATIC_ASSERT_LVALUE(XprType) - return m_xpr.const_cast_derived() - .coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), - m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); - } - - inline const Scalar& coeffRef(Index index) const - { - return m_xpr.const_cast_derived() - .coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), - m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); - } - - inline const CoeffReturnType coeff(Index index) const - { - return m_xpr - .coeff(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), - m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); - } - - template - inline PacketScalar packet(Index rowId, Index colId) const - { - return m_xpr.template packet - (rowId + m_startRow.value(), colId + m_startCol.value()); - } - - template - inline void writePacket(Index rowId, Index colId, const PacketScalar& val) - { - m_xpr.const_cast_derived().template writePacket - (rowId + m_startRow.value(), colId + m_startCol.value(), val); - } - - template - inline PacketScalar packet(Index index) const - { - return m_xpr.template packet - (m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), - m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0)); - } - - template - inline void writePacket(Index index, const PacketScalar& val) - { - m_xpr.const_cast_derived().template writePacket - (m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), - m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0), val); - } - - #ifdef EIGEN_PARSED_BY_DOXYGEN - /** \sa MapBase::data() */ - inline const Scalar* data() const; - inline Index innerStride() const; - inline Index outerStride() const; - #endif - - const typename internal::remove_all::type& nestedExpression() const - { - return m_xpr; - } - - Index startRow() const - { - return m_startRow.value(); - } - - Index startCol() const - { - return m_startCol.value(); - } - - protected: - - const typename XprType::Nested m_xpr; - const internal::variable_if_dynamic m_startRow; - const internal::variable_if_dynamic m_startCol; - const internal::variable_if_dynamic m_blockRows; - const internal::variable_if_dynamic m_blockCols; -}; - -/** \internal Internal implementation of dense Blocks in the direct access case.*/ -template -class BlockImpl_dense - : public MapBase > -{ - typedef Block BlockType; - public: - - typedef MapBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(BlockType) - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl_dense) - - /** Column or Row constructor - */ - inline BlockImpl_dense(XprType& xpr, Index i) - : Base(internal::const_cast_ptr(&xpr.coeffRef( - (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0, - (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0)), - BlockRows==1 ? 1 : xpr.rows(), - BlockCols==1 ? 1 : xpr.cols()), - m_xpr(xpr) - { - init(); - } - - /** Fixed-size constructor - */ - inline BlockImpl_dense(XprType& xpr, Index startRow, Index startCol) - : Base(internal::const_cast_ptr(&xpr.coeffRef(startRow,startCol))), m_xpr(xpr) - { - init(); - } - - /** Dynamic-size constructor - */ - inline BlockImpl_dense(XprType& xpr, - Index startRow, Index startCol, - Index blockRows, Index blockCols) - : Base(internal::const_cast_ptr(&xpr.coeffRef(startRow,startCol)), blockRows, blockCols), - m_xpr(xpr) - { - init(); - } - - const typename internal::remove_all::type& nestedExpression() const - { - return m_xpr; - } - - /** \sa MapBase::innerStride() */ - inline Index innerStride() const - { - return internal::traits::HasSameStorageOrderAsXprType - ? m_xpr.innerStride() - : m_xpr.outerStride(); - } - - /** \sa MapBase::outerStride() */ - inline Index outerStride() const - { - return m_outerStride; - } - - #ifndef __SUNPRO_CC - // FIXME sunstudio is not friendly with the above friend... - // META-FIXME there is no 'friend' keyword around here. Is this obsolete? - protected: - #endif - - #ifndef EIGEN_PARSED_BY_DOXYGEN - /** \internal used by allowAligned() */ - inline BlockImpl_dense(XprType& xpr, const Scalar* data, Index blockRows, Index blockCols) - : Base(data, blockRows, blockCols), m_xpr(xpr) - { - init(); - } - #endif - - protected: - void init() - { - m_outerStride = internal::traits::HasSameStorageOrderAsXprType - ? m_xpr.outerStride() - : m_xpr.innerStride(); - } - - typename XprType::Nested m_xpr; - Index m_outerStride; -}; - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_BLOCK_H diff --git a/splinter/src/Core/BooleanRedux.h b/splinter/src/Core/BooleanRedux.h deleted file mode 100644 index be9f48a8c7..0000000000 --- a/splinter/src/Core/BooleanRedux.h +++ /dev/null @@ -1,154 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_ALLANDANY_H -#define EIGEN_ALLANDANY_H - -namespace Eigen { - -namespace internal { - -template -struct all_unroller -{ - enum { - col = (UnrollCount-1) / Derived::RowsAtCompileTime, - row = (UnrollCount-1) % Derived::RowsAtCompileTime - }; - - static inline bool run(const Derived &mat) - { - return all_unroller::run(mat) && mat.coeff(row, col); - } -}; - -template -struct all_unroller -{ - static inline bool run(const Derived &/*mat*/) { return true; } -}; - -template -struct all_unroller -{ - static inline bool run(const Derived &) { return false; } -}; - -template -struct any_unroller -{ - enum { - col = (UnrollCount-1) / Derived::RowsAtCompileTime, - row = (UnrollCount-1) % Derived::RowsAtCompileTime - }; - - static inline bool run(const Derived &mat) - { - return any_unroller::run(mat) || mat.coeff(row, col); - } -}; - -template -struct any_unroller -{ - static inline bool run(const Derived & /*mat*/) { return false; } -}; - -template -struct any_unroller -{ - static inline bool run(const Derived &) { return false; } -}; - -} // end namespace internal - -/** \returns true if all coefficients are true - * - * Example: \include MatrixBase_all.cpp - * Output: \verbinclude MatrixBase_all.out - * - * \sa any(), Cwise::operator<() - */ -template -inline bool DenseBase::all() const -{ - enum { - unroll = SizeAtCompileTime != Dynamic - && CoeffReadCost != Dynamic - && NumTraits::AddCost != Dynamic - && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT - }; - if(unroll) - return internal::all_unroller::run(derived()); - else - { - for(Index j = 0; j < cols(); ++j) - for(Index i = 0; i < rows(); ++i) - if (!coeff(i, j)) return false; - return true; - } -} - -/** \returns true if at least one coefficient is true - * - * \sa all() - */ -template -inline bool DenseBase::any() const -{ - enum { - unroll = SizeAtCompileTime != Dynamic - && CoeffReadCost != Dynamic - && NumTraits::AddCost != Dynamic - && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT - }; - if(unroll) - return internal::any_unroller::run(derived()); - else - { - for(Index j = 0; j < cols(); ++j) - for(Index i = 0; i < rows(); ++i) - if (coeff(i, j)) return true; - return false; - } -} - -/** \returns the number of coefficients which evaluate to true - * - * \sa all(), any() - */ -template -inline typename DenseBase::Index DenseBase::count() const -{ - return derived().template cast().template cast().sum(); -} - -/** \returns true is \c *this contains at least one Not A Number (NaN). - * - * \sa allFinite() - */ -template -inline bool DenseBase::hasNaN() const -{ - return !((derived().array()==derived().array()).all()); -} - -/** \returns true if \c *this contains only finite numbers, i.e., no NaN and no +/-INF values. - * - * \sa hasNaN() - */ -template -inline bool DenseBase::allFinite() const -{ - return !((derived()-derived()).hasNaN()); -} - -} // end namespace Eigen - -#endif // EIGEN_ALLANDANY_H diff --git a/splinter/src/Core/CommaInitializer.h b/splinter/src/Core/CommaInitializer.h deleted file mode 100644 index a036d8c3bc..0000000000 --- a/splinter/src/Core/CommaInitializer.h +++ /dev/null @@ -1,154 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_COMMAINITIALIZER_H -#define EIGEN_COMMAINITIALIZER_H - -namespace Eigen { - -/** \class CommaInitializer - * \ingroup Core_Module - * - * \brief Helper class used by the comma initializer operator - * - * This class is internally used to implement the comma initializer feature. It is - * the return type of MatrixBase::operator<<, and most of the time this is the only - * way it is used. - * - * \sa \ref MatrixBaseCommaInitRef "MatrixBase::operator<<", CommaInitializer::finished() - */ -template -struct CommaInitializer -{ - typedef typename XprType::Scalar Scalar; - typedef typename XprType::Index Index; - - inline CommaInitializer(XprType& xpr, const Scalar& s) - : m_xpr(xpr), m_row(0), m_col(1), m_currentBlockRows(1) - { - m_xpr.coeffRef(0,0) = s; - } - - template - inline CommaInitializer(XprType& xpr, const DenseBase& other) - : m_xpr(xpr), m_row(0), m_col(other.cols()), m_currentBlockRows(other.rows()) - { - m_xpr.block(0, 0, other.rows(), other.cols()) = other; - } - - /* Copy/Move constructor which transfers ownership. This is crucial in - * absence of return value optimization to avoid assertions during destruction. */ - // FIXME in C++11 mode this could be replaced by a proper RValue constructor - inline CommaInitializer(const CommaInitializer& o) - : m_xpr(o.m_xpr), m_row(o.m_row), m_col(o.m_col), m_currentBlockRows(o.m_currentBlockRows) { - // Mark original object as finished. In absence of R-value references we need to const_cast: - const_cast(o).m_row = m_xpr.rows(); - const_cast(o).m_col = m_xpr.cols(); - const_cast(o).m_currentBlockRows = 0; - } - - /* inserts a scalar value in the target matrix */ - CommaInitializer& operator,(const Scalar& s) - { - if (m_col==m_xpr.cols()) - { - m_row+=m_currentBlockRows; - m_col = 0; - m_currentBlockRows = 1; - eigen_assert(m_row - CommaInitializer& operator,(const DenseBase& other) - { - if(other.cols()==0 || other.rows()==0) - return *this; - if (m_col==m_xpr.cols()) - { - m_row+=m_currentBlockRows; - m_col = 0; - m_currentBlockRows = other.rows(); - eigen_assert(m_row+m_currentBlockRows<=m_xpr.rows() - && "Too many rows passed to comma initializer (operator<<)"); - } - eigen_assert(m_col - (m_row, m_col) = other; - else - m_xpr.block(m_row, m_col, other.rows(), other.cols()) = other; - m_col += other.cols(); - return *this; - } - - inline ~CommaInitializer() - { - eigen_assert((m_row+m_currentBlockRows) == m_xpr.rows() - && m_col == m_xpr.cols() - && "Too few coefficients passed to comma initializer (operator<<)"); - } - - /** \returns the built matrix once all its coefficients have been set. - * Calling finished is 100% optional. Its purpose is to write expressions - * like this: - * \code - * quaternion.fromRotationMatrix((Matrix3f() << axis0, axis1, axis2).finished()); - * \endcode - */ - inline XprType& finished() { return m_xpr; } - - XprType& m_xpr; // target expression - Index m_row; // current row id - Index m_col; // current col id - Index m_currentBlockRows; // current block height -}; - -/** \anchor MatrixBaseCommaInitRef - * Convenient operator to set the coefficients of a matrix. - * - * The coefficients must be provided in a row major order and exactly match - * the size of the matrix. Otherwise an assertion is raised. - * - * Example: \include MatrixBase_set.cpp - * Output: \verbinclude MatrixBase_set.out - * - * \note According the c++ standard, the argument expressions of this comma initializer are evaluated in arbitrary order. - * - * \sa CommaInitializer::finished(), class CommaInitializer - */ -template -inline CommaInitializer DenseBase::operator<< (const Scalar& s) -{ - return CommaInitializer(*static_cast(this), s); -} - -/** \sa operator<<(const Scalar&) */ -template -template -inline CommaInitializer -DenseBase::operator<<(const DenseBase& other) -{ - return CommaInitializer(*static_cast(this), other); -} - -} // end namespace Eigen - -#endif // EIGEN_COMMAINITIALIZER_H diff --git a/splinter/src/Core/CoreIterators.h b/splinter/src/Core/CoreIterators.h deleted file mode 100644 index 6da4683d2c..0000000000 --- a/splinter/src/Core/CoreIterators.h +++ /dev/null @@ -1,61 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_COREITERATORS_H -#define EIGEN_COREITERATORS_H - -namespace Eigen { - -/* This file contains the respective InnerIterator definition of the expressions defined in Eigen/Core - */ - -/** \ingroup SparseCore_Module - * \class InnerIterator - * \brief An InnerIterator allows to loop over the element of a sparse (or dense) matrix or expression - * - * todo - */ - -// generic version for dense matrix and expressions -template class DenseBase::InnerIterator -{ - protected: - typedef typename Derived::Scalar Scalar; - typedef typename Derived::Index Index; - - enum { IsRowMajor = (Derived::Flags&RowMajorBit)==RowMajorBit }; - public: - EIGEN_STRONG_INLINE InnerIterator(const Derived& expr, Index outer) - : m_expression(expr), m_inner(0), m_outer(outer), m_end(expr.innerSize()) - {} - - EIGEN_STRONG_INLINE Scalar value() const - { - return (IsRowMajor) ? m_expression.coeff(m_outer, m_inner) - : m_expression.coeff(m_inner, m_outer); - } - - EIGEN_STRONG_INLINE InnerIterator& operator++() { m_inner++; return *this; } - - EIGEN_STRONG_INLINE Index index() const { return m_inner; } - inline Index row() const { return IsRowMajor ? m_outer : index(); } - inline Index col() const { return IsRowMajor ? index() : m_outer; } - - EIGEN_STRONG_INLINE operator bool() const { return m_inner < m_end && m_inner>=0; } - - protected: - const Derived& m_expression; - Index m_inner; - const Index m_outer; - const Index m_end; -}; - -} // end namespace Eigen - -#endif // EIGEN_COREITERATORS_H diff --git a/splinter/src/Core/CwiseBinaryOp.h b/splinter/src/Core/CwiseBinaryOp.h deleted file mode 100644 index 519a866e60..0000000000 --- a/splinter/src/Core/CwiseBinaryOp.h +++ /dev/null @@ -1,230 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_CWISE_BINARY_OP_H -#define EIGEN_CWISE_BINARY_OP_H - -namespace Eigen { - -/** \class CwiseBinaryOp - * \ingroup Core_Module - * - * \brief Generic expression where a coefficient-wise binary operator is applied to two expressions - * - * \param BinaryOp template functor implementing the operator - * \param Lhs the type of the left-hand side - * \param Rhs the type of the right-hand side - * - * This class represents an expression where a coefficient-wise binary operator is applied to two expressions. - * It is the return type of binary operators, by which we mean only those binary operators where - * both the left-hand side and the right-hand side are Eigen expressions. - * For example, the return type of matrix1+matrix2 is a CwiseBinaryOp. - * - * Most of the time, this is the only way that it is used, so you typically don't have to name - * CwiseBinaryOp types explicitly. - * - * \sa MatrixBase::binaryExpr(const MatrixBase &,const CustomBinaryOp &) const, class CwiseUnaryOp, class CwiseNullaryOp - */ - -namespace internal { -template -struct traits > -{ - // we must not inherit from traits since it has - // the potential to cause problems with MSVC - typedef typename remove_all::type Ancestor; - typedef typename traits::XprKind XprKind; - enum { - RowsAtCompileTime = traits::RowsAtCompileTime, - ColsAtCompileTime = traits::ColsAtCompileTime, - MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, - MaxColsAtCompileTime = traits::MaxColsAtCompileTime - }; - - // even though we require Lhs and Rhs to have the same scalar type (see CwiseBinaryOp constructor), - // we still want to handle the case when the result type is different. - typedef typename result_of< - BinaryOp( - typename Lhs::Scalar, - typename Rhs::Scalar - ) - >::type Scalar; - typedef typename promote_storage_type::StorageKind, - typename traits::StorageKind>::ret StorageKind; - typedef typename promote_index_type::Index, - typename traits::Index>::type Index; - typedef typename Lhs::Nested LhsNested; - typedef typename Rhs::Nested RhsNested; - typedef typename remove_reference::type _LhsNested; - typedef typename remove_reference::type _RhsNested; - enum { - LhsCoeffReadCost = _LhsNested::CoeffReadCost, - RhsCoeffReadCost = _RhsNested::CoeffReadCost, - LhsFlags = _LhsNested::Flags, - RhsFlags = _RhsNested::Flags, - SameType = is_same::value, - StorageOrdersAgree = (int(Lhs::Flags)&RowMajorBit)==(int(Rhs::Flags)&RowMajorBit), - Flags0 = (int(LhsFlags) | int(RhsFlags)) & ( - HereditaryBits - | (int(LhsFlags) & int(RhsFlags) & - ( AlignedBit - | (StorageOrdersAgree ? LinearAccessBit : 0) - | (functor_traits::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0) - ) - ) - ), - Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit), - Cost0 = EIGEN_ADD_COST(LhsCoeffReadCost,RhsCoeffReadCost), - CoeffReadCost = EIGEN_ADD_COST(Cost0,functor_traits::Cost) - }; -}; -} // end namespace internal - -// we require Lhs and Rhs to have the same scalar type. Currently there is no example of a binary functor -// that would take two operands of different types. If there were such an example, then this check should be -// moved to the BinaryOp functors, on a per-case basis. This would however require a change in the BinaryOp functors, as -// currently they take only one typename Scalar template parameter. -// It is tempting to always allow mixing different types but remember that this is often impossible in the vectorized paths. -// So allowing mixing different types gives very unexpected errors when enabling vectorization, when the user tries to -// add together a float matrix and a double matrix. -#define EIGEN_CHECK_BINARY_COMPATIBILIY(BINOP,LHS,RHS) \ - EIGEN_STATIC_ASSERT((internal::functor_is_product_like::ret \ - ? int(internal::scalar_product_traits::Defined) \ - : int(internal::is_same::value)), \ - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - -template -class CwiseBinaryOpImpl; - -template -class CwiseBinaryOp : internal::no_assignment_operator, - public CwiseBinaryOpImpl< - BinaryOp, Lhs, Rhs, - typename internal::promote_storage_type::StorageKind, - typename internal::traits::StorageKind>::ret> -{ - public: - - typedef typename CwiseBinaryOpImpl< - BinaryOp, Lhs, Rhs, - typename internal::promote_storage_type::StorageKind, - typename internal::traits::StorageKind>::ret>::Base Base; - EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseBinaryOp) - - typedef typename internal::nested::type LhsNested; - typedef typename internal::nested::type RhsNested; - typedef typename internal::remove_reference::type _LhsNested; - typedef typename internal::remove_reference::type _RhsNested; - - EIGEN_STRONG_INLINE CwiseBinaryOp(const Lhs& aLhs, const Rhs& aRhs, const BinaryOp& func = BinaryOp()) - : m_lhs(aLhs), m_rhs(aRhs), m_functor(func) - { - EIGEN_CHECK_BINARY_COMPATIBILIY(BinaryOp,typename Lhs::Scalar,typename Rhs::Scalar); - // require the sizes to match - EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Lhs, Rhs) - eigen_assert(aLhs.rows() == aRhs.rows() && aLhs.cols() == aRhs.cols()); - } - - EIGEN_STRONG_INLINE Index rows() const { - // return the fixed size type if available to enable compile time optimizations - if (internal::traits::type>::RowsAtCompileTime==Dynamic) - return m_rhs.rows(); - else - return m_lhs.rows(); - } - EIGEN_STRONG_INLINE Index cols() const { - // return the fixed size type if available to enable compile time optimizations - if (internal::traits::type>::ColsAtCompileTime==Dynamic) - return m_rhs.cols(); - else - return m_lhs.cols(); - } - - /** \returns the left hand side nested expression */ - const _LhsNested& lhs() const { return m_lhs; } - /** \returns the right hand side nested expression */ - const _RhsNested& rhs() const { return m_rhs; } - /** \returns the functor representing the binary operation */ - const BinaryOp& functor() const { return m_functor; } - - protected: - LhsNested m_lhs; - RhsNested m_rhs; - const BinaryOp m_functor; -}; - -template -class CwiseBinaryOpImpl - : public internal::dense_xpr_base >::type -{ - typedef CwiseBinaryOp Derived; - public: - - typedef typename internal::dense_xpr_base >::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE( Derived ) - - EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const - { - return derived().functor()(derived().lhs().coeff(rowId, colId), - derived().rhs().coeff(rowId, colId)); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const - { - return derived().functor().packetOp(derived().lhs().template packet(rowId, colId), - derived().rhs().template packet(rowId, colId)); - } - - EIGEN_STRONG_INLINE const Scalar coeff(Index index) const - { - return derived().functor()(derived().lhs().coeff(index), - derived().rhs().coeff(index)); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index index) const - { - return derived().functor().packetOp(derived().lhs().template packet(index), - derived().rhs().template packet(index)); - } -}; - -/** replaces \c *this by \c *this - \a other. - * - * \returns a reference to \c *this - */ -template -template -EIGEN_STRONG_INLINE Derived & -MatrixBase::operator-=(const MatrixBase &other) -{ - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); - return derived(); -} - -/** replaces \c *this by \c *this + \a other. - * - * \returns a reference to \c *this - */ -template -template -EIGEN_STRONG_INLINE Derived & -MatrixBase::operator+=(const MatrixBase& other) -{ - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); - return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_CWISE_BINARY_OP_H diff --git a/splinter/src/Core/CwiseNullaryOp.h b/splinter/src/Core/CwiseNullaryOp.h deleted file mode 100644 index a93bab2d0f..0000000000 --- a/splinter/src/Core/CwiseNullaryOp.h +++ /dev/null @@ -1,864 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_CWISE_NULLARY_OP_H -#define EIGEN_CWISE_NULLARY_OP_H - -namespace Eigen { - -/** \class CwiseNullaryOp - * \ingroup Core_Module - * - * \brief Generic expression of a matrix where all coefficients are defined by a functor - * - * \param NullaryOp template functor implementing the operator - * \param PlainObjectType the underlying plain matrix/array type - * - * This class represents an expression of a generic nullary operator. - * It is the return type of the Ones(), Zero(), Constant(), Identity() and Random() methods, - * and most of the time this is the only way it is used. - * - * However, if you want to write a function returning such an expression, you - * will need to use this class. - * - * \sa class CwiseUnaryOp, class CwiseBinaryOp, DenseBase::NullaryExpr() - */ - -namespace internal { -template -struct traits > : traits -{ - enum { - Flags = (traits::Flags - & ( HereditaryBits - | (functor_has_linear_access::ret ? LinearAccessBit : 0) - | (functor_traits::PacketAccess ? PacketAccessBit : 0))) - | (functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit), - CoeffReadCost = functor_traits::Cost - }; -}; -} - -template -class CwiseNullaryOp : internal::no_assignment_operator, - public internal::dense_xpr_base< CwiseNullaryOp >::type -{ - public: - - typedef typename internal::dense_xpr_base::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(CwiseNullaryOp) - - CwiseNullaryOp(Index nbRows, Index nbCols, const NullaryOp& func = NullaryOp()) - : m_rows(nbRows), m_cols(nbCols), m_functor(func) - { - eigen_assert(nbRows >= 0 - && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == nbRows) - && nbCols >= 0 - && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == nbCols)); - } - - EIGEN_STRONG_INLINE Index rows() const { return m_rows.value(); } - EIGEN_STRONG_INLINE Index cols() const { return m_cols.value(); } - - EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const - { - return m_functor(rowId, colId); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const - { - return m_functor.packetOp(rowId, colId); - } - - EIGEN_STRONG_INLINE const Scalar coeff(Index index) const - { - return m_functor(index); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index index) const - { - return m_functor.packetOp(index); - } - - /** \returns the functor representing the nullary operation */ - const NullaryOp& functor() const { return m_functor; } - - protected: - const internal::variable_if_dynamic m_rows; - const internal::variable_if_dynamic m_cols; - const NullaryOp m_functor; -}; - - -/** \returns an expression of a matrix defined by a custom functor \a func - * - * The parameters \a rows and \a cols are the number of rows and of columns of - * the returned matrix. Must be compatible with this MatrixBase type. - * - * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, - * it is redundant to pass \a rows and \a cols as arguments, so Zero() should be used - * instead. - * - * The template parameter \a CustomNullaryOp is the type of the functor. - * - * \sa class CwiseNullaryOp - */ -template -template -EIGEN_STRONG_INLINE const CwiseNullaryOp -DenseBase::NullaryExpr(Index rows, Index cols, const CustomNullaryOp& func) -{ - return CwiseNullaryOp(rows, cols, func); -} - -/** \returns an expression of a matrix defined by a custom functor \a func - * - * The parameter \a size is the size of the returned vector. - * Must be compatible with this MatrixBase type. - * - * \only_for_vectors - * - * This variant is meant to be used for dynamic-size vector types. For fixed-size types, - * it is redundant to pass \a size as argument, so Zero() should be used - * instead. - * - * The template parameter \a CustomNullaryOp is the type of the functor. - * - * \sa class CwiseNullaryOp - */ -template -template -EIGEN_STRONG_INLINE const CwiseNullaryOp -DenseBase::NullaryExpr(Index size, const CustomNullaryOp& func) -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - if(RowsAtCompileTime == 1) return CwiseNullaryOp(1, size, func); - else return CwiseNullaryOp(size, 1, func); -} - -/** \returns an expression of a matrix defined by a custom functor \a func - * - * This variant is only for fixed-size DenseBase types. For dynamic-size types, you - * need to use the variants taking size arguments. - * - * The template parameter \a CustomNullaryOp is the type of the functor. - * - * \sa class CwiseNullaryOp - */ -template -template -EIGEN_STRONG_INLINE const CwiseNullaryOp -DenseBase::NullaryExpr(const CustomNullaryOp& func) -{ - return CwiseNullaryOp(RowsAtCompileTime, ColsAtCompileTime, func); -} - -/** \returns an expression of a constant matrix of value \a value - * - * The parameters \a nbRows and \a nbCols are the number of rows and of columns of - * the returned matrix. Must be compatible with this DenseBase type. - * - * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, - * it is redundant to pass \a nbRows and \a nbCols as arguments, so Zero() should be used - * instead. - * - * The template parameter \a CustomNullaryOp is the type of the functor. - * - * \sa class CwiseNullaryOp - */ -template -EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType -DenseBase::Constant(Index nbRows, Index nbCols, const Scalar& value) -{ - return DenseBase::NullaryExpr(nbRows, nbCols, internal::scalar_constant_op(value)); -} - -/** \returns an expression of a constant matrix of value \a value - * - * The parameter \a size is the size of the returned vector. - * Must be compatible with this DenseBase type. - * - * \only_for_vectors - * - * This variant is meant to be used for dynamic-size vector types. For fixed-size types, - * it is redundant to pass \a size as argument, so Zero() should be used - * instead. - * - * The template parameter \a CustomNullaryOp is the type of the functor. - * - * \sa class CwiseNullaryOp - */ -template -EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType -DenseBase::Constant(Index size, const Scalar& value) -{ - return DenseBase::NullaryExpr(size, internal::scalar_constant_op(value)); -} - -/** \returns an expression of a constant matrix of value \a value - * - * This variant is only for fixed-size DenseBase types. For dynamic-size types, you - * need to use the variants taking size arguments. - * - * The template parameter \a CustomNullaryOp is the type of the functor. - * - * \sa class CwiseNullaryOp - */ -template -EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType -DenseBase::Constant(const Scalar& value) -{ - EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) - return DenseBase::NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_constant_op(value)); -} - -/** - * \brief Sets a linearly space vector. - * - * The function generates 'size' equally spaced values in the closed interval [low,high]. - * This particular version of LinSpaced() uses sequential access, i.e. vector access is - * assumed to be a(0), a(1), ..., a(size). This assumption allows for better vectorization - * and yields faster code than the random access version. - * - * When size is set to 1, a vector of length 1 containing 'high' is returned. - * - * \only_for_vectors - * - * Example: \include DenseBase_LinSpaced_seq.cpp - * Output: \verbinclude DenseBase_LinSpaced_seq.out - * - * \sa setLinSpaced(Index,const Scalar&,const Scalar&), LinSpaced(Index,Scalar,Scalar), CwiseNullaryOp - */ -template -EIGEN_STRONG_INLINE const typename DenseBase::SequentialLinSpacedReturnType -DenseBase::LinSpaced(Sequential_t, Index size, const Scalar& low, const Scalar& high) -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); -} - -/** - * \copydoc DenseBase::LinSpaced(Sequential_t, Index, const Scalar&, const Scalar&) - * Special version for fixed size types which does not require the size parameter. - */ -template -EIGEN_STRONG_INLINE const typename DenseBase::SequentialLinSpacedReturnType -DenseBase::LinSpaced(Sequential_t, const Scalar& low, const Scalar& high) -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) - return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); -} - -/** - * \brief Sets a linearly space vector. - * - * The function generates 'size' equally spaced values in the closed interval [low,high]. - * When size is set to 1, a vector of length 1 containing 'high' is returned. - * - * \only_for_vectors - * - * Example: \include DenseBase_LinSpaced.cpp - * Output: \verbinclude DenseBase_LinSpaced.out - * - * \sa setLinSpaced(Index,const Scalar&,const Scalar&), LinSpaced(Sequential_t,Index,const Scalar&,const Scalar&,Index), CwiseNullaryOp - */ -template -EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType -DenseBase::LinSpaced(Index size, const Scalar& low, const Scalar& high) -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); -} - -/** - * \copydoc DenseBase::LinSpaced(Index, const Scalar&, const Scalar&) - * Special version for fixed size types which does not require the size parameter. - */ -template -EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType -DenseBase::LinSpaced(const Scalar& low, const Scalar& high) -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) - return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); -} - -/** \returns true if all coefficients in this matrix are approximately equal to \a val, to within precision \a prec */ -template -bool DenseBase::isApproxToConstant -(const Scalar& val, const RealScalar& prec) const -{ - for(Index j = 0; j < cols(); ++j) - for(Index i = 0; i < rows(); ++i) - if(!internal::isApprox(this->coeff(i, j), val, prec)) - return false; - return true; -} - -/** This is just an alias for isApproxToConstant(). - * - * \returns true if all coefficients in this matrix are approximately equal to \a value, to within precision \a prec */ -template -bool DenseBase::isConstant -(const Scalar& val, const RealScalar& prec) const -{ - return isApproxToConstant(val, prec); -} - -/** Alias for setConstant(): sets all coefficients in this expression to \a val. - * - * \sa setConstant(), Constant(), class CwiseNullaryOp - */ -template -EIGEN_STRONG_INLINE void DenseBase::fill(const Scalar& val) -{ - setConstant(val); -} - -/** Sets all coefficients in this expression to \a value. - * - * \sa fill(), setConstant(Index,const Scalar&), setConstant(Index,Index,const Scalar&), setZero(), setOnes(), Constant(), class CwiseNullaryOp, setZero(), setOnes() - */ -template -EIGEN_STRONG_INLINE Derived& DenseBase::setConstant(const Scalar& val) -{ - return derived() = Constant(rows(), cols(), val); -} - -/** Resizes to the given \a size, and sets all coefficients in this expression to the given \a value. - * - * \only_for_vectors - * - * Example: \include Matrix_setConstant_int.cpp - * Output: \verbinclude Matrix_setConstant_int.out - * - * \sa MatrixBase::setConstant(const Scalar&), setConstant(Index,Index,const Scalar&), class CwiseNullaryOp, MatrixBase::Constant(const Scalar&) - */ -template -EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setConstant(Index size, const Scalar& val) -{ - resize(size); - return setConstant(val); -} - -/** Resizes to the given size, and sets all coefficients in this expression to the given \a value. - * - * \param nbRows the new number of rows - * \param nbCols the new number of columns - * \param val the value to which all coefficients are set - * - * Example: \include Matrix_setConstant_int_int.cpp - * Output: \verbinclude Matrix_setConstant_int_int.out - * - * \sa MatrixBase::setConstant(const Scalar&), setConstant(Index,const Scalar&), class CwiseNullaryOp, MatrixBase::Constant(const Scalar&) - */ -template -EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setConstant(Index nbRows, Index nbCols, const Scalar& val) -{ - resize(nbRows, nbCols); - return setConstant(val); -} - -/** - * \brief Sets a linearly space vector. - * - * The function generates 'size' equally spaced values in the closed interval [low,high]. - * When size is set to 1, a vector of length 1 containing 'high' is returned. - * - * \only_for_vectors - * - * Example: \include DenseBase_setLinSpaced.cpp - * Output: \verbinclude DenseBase_setLinSpaced.out - * - * \sa CwiseNullaryOp - */ -template -EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(Index newSize, const Scalar& low, const Scalar& high) -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return derived() = Derived::NullaryExpr(newSize, internal::linspaced_op(low,high,newSize)); -} - -/** - * \brief Sets a linearly space vector. - * - * The function fill *this with equally spaced values in the closed interval [low,high]. - * When size is set to 1, a vector of length 1 containing 'high' is returned. - * - * \only_for_vectors - * - * \sa setLinSpaced(Index, const Scalar&, const Scalar&), CwiseNullaryOp - */ -template -EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(const Scalar& low, const Scalar& high) -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return setLinSpaced(size(), low, high); -} - -// zero: - -/** \returns an expression of a zero matrix. - * - * The parameters \a rows and \a cols are the number of rows and of columns of - * the returned matrix. Must be compatible with this MatrixBase type. - * - * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, - * it is redundant to pass \a rows and \a cols as arguments, so Zero() should be used - * instead. - * - * Example: \include MatrixBase_zero_int_int.cpp - * Output: \verbinclude MatrixBase_zero_int_int.out - * - * \sa Zero(), Zero(Index) - */ -template -EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType -DenseBase::Zero(Index nbRows, Index nbCols) -{ - return Constant(nbRows, nbCols, Scalar(0)); -} - -/** \returns an expression of a zero vector. - * - * The parameter \a size is the size of the returned vector. - * Must be compatible with this MatrixBase type. - * - * \only_for_vectors - * - * This variant is meant to be used for dynamic-size vector types. For fixed-size types, - * it is redundant to pass \a size as argument, so Zero() should be used - * instead. - * - * Example: \include MatrixBase_zero_int.cpp - * Output: \verbinclude MatrixBase_zero_int.out - * - * \sa Zero(), Zero(Index,Index) - */ -template -EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType -DenseBase::Zero(Index size) -{ - return Constant(size, Scalar(0)); -} - -/** \returns an expression of a fixed-size zero matrix or vector. - * - * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you - * need to use the variants taking size arguments. - * - * Example: \include MatrixBase_zero.cpp - * Output: \verbinclude MatrixBase_zero.out - * - * \sa Zero(Index), Zero(Index,Index) - */ -template -EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType -DenseBase::Zero() -{ - return Constant(Scalar(0)); -} - -/** \returns true if *this is approximately equal to the zero matrix, - * within the precision given by \a prec. - * - * Example: \include MatrixBase_isZero.cpp - * Output: \verbinclude MatrixBase_isZero.out - * - * \sa class CwiseNullaryOp, Zero() - */ -template -bool DenseBase::isZero(const RealScalar& prec) const -{ - for(Index j = 0; j < cols(); ++j) - for(Index i = 0; i < rows(); ++i) - if(!internal::isMuchSmallerThan(this->coeff(i, j), static_cast(1), prec)) - return false; - return true; -} - -/** Sets all coefficients in this expression to zero. - * - * Example: \include MatrixBase_setZero.cpp - * Output: \verbinclude MatrixBase_setZero.out - * - * \sa class CwiseNullaryOp, Zero() - */ -template -EIGEN_STRONG_INLINE Derived& DenseBase::setZero() -{ - return setConstant(Scalar(0)); -} - -/** Resizes to the given \a size, and sets all coefficients in this expression to zero. - * - * \only_for_vectors - * - * Example: \include Matrix_setZero_int.cpp - * Output: \verbinclude Matrix_setZero_int.out - * - * \sa DenseBase::setZero(), setZero(Index,Index), class CwiseNullaryOp, DenseBase::Zero() - */ -template -EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setZero(Index newSize) -{ - resize(newSize); - return setConstant(Scalar(0)); -} - -/** Resizes to the given size, and sets all coefficients in this expression to zero. - * - * \param nbRows the new number of rows - * \param nbCols the new number of columns - * - * Example: \include Matrix_setZero_int_int.cpp - * Output: \verbinclude Matrix_setZero_int_int.out - * - * \sa DenseBase::setZero(), setZero(Index), class CwiseNullaryOp, DenseBase::Zero() - */ -template -EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setZero(Index nbRows, Index nbCols) -{ - resize(nbRows, nbCols); - return setConstant(Scalar(0)); -} - -// ones: - -/** \returns an expression of a matrix where all coefficients equal one. - * - * The parameters \a nbRows and \a nbCols are the number of rows and of columns of - * the returned matrix. Must be compatible with this MatrixBase type. - * - * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, - * it is redundant to pass \a rows and \a cols as arguments, so Ones() should be used - * instead. - * - * Example: \include MatrixBase_ones_int_int.cpp - * Output: \verbinclude MatrixBase_ones_int_int.out - * - * \sa Ones(), Ones(Index), isOnes(), class Ones - */ -template -EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType -DenseBase::Ones(Index nbRows, Index nbCols) -{ - return Constant(nbRows, nbCols, Scalar(1)); -} - -/** \returns an expression of a vector where all coefficients equal one. - * - * The parameter \a newSize is the size of the returned vector. - * Must be compatible with this MatrixBase type. - * - * \only_for_vectors - * - * This variant is meant to be used for dynamic-size vector types. For fixed-size types, - * it is redundant to pass \a size as argument, so Ones() should be used - * instead. - * - * Example: \include MatrixBase_ones_int.cpp - * Output: \verbinclude MatrixBase_ones_int.out - * - * \sa Ones(), Ones(Index,Index), isOnes(), class Ones - */ -template -EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType -DenseBase::Ones(Index newSize) -{ - return Constant(newSize, Scalar(1)); -} - -/** \returns an expression of a fixed-size matrix or vector where all coefficients equal one. - * - * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you - * need to use the variants taking size arguments. - * - * Example: \include MatrixBase_ones.cpp - * Output: \verbinclude MatrixBase_ones.out - * - * \sa Ones(Index), Ones(Index,Index), isOnes(), class Ones - */ -template -EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType -DenseBase::Ones() -{ - return Constant(Scalar(1)); -} - -/** \returns true if *this is approximately equal to the matrix where all coefficients - * are equal to 1, within the precision given by \a prec. - * - * Example: \include MatrixBase_isOnes.cpp - * Output: \verbinclude MatrixBase_isOnes.out - * - * \sa class CwiseNullaryOp, Ones() - */ -template -bool DenseBase::isOnes -(const RealScalar& prec) const -{ - return isApproxToConstant(Scalar(1), prec); -} - -/** Sets all coefficients in this expression to one. - * - * Example: \include MatrixBase_setOnes.cpp - * Output: \verbinclude MatrixBase_setOnes.out - * - * \sa class CwiseNullaryOp, Ones() - */ -template -EIGEN_STRONG_INLINE Derived& DenseBase::setOnes() -{ - return setConstant(Scalar(1)); -} - -/** Resizes to the given \a newSize, and sets all coefficients in this expression to one. - * - * \only_for_vectors - * - * Example: \include Matrix_setOnes_int.cpp - * Output: \verbinclude Matrix_setOnes_int.out - * - * \sa MatrixBase::setOnes(), setOnes(Index,Index), class CwiseNullaryOp, MatrixBase::Ones() - */ -template -EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setOnes(Index newSize) -{ - resize(newSize); - return setConstant(Scalar(1)); -} - -/** Resizes to the given size, and sets all coefficients in this expression to one. - * - * \param nbRows the new number of rows - * \param nbCols the new number of columns - * - * Example: \include Matrix_setOnes_int_int.cpp - * Output: \verbinclude Matrix_setOnes_int_int.out - * - * \sa MatrixBase::setOnes(), setOnes(Index), class CwiseNullaryOp, MatrixBase::Ones() - */ -template -EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setOnes(Index nbRows, Index nbCols) -{ - resize(nbRows, nbCols); - return setConstant(Scalar(1)); -} - -// Identity: - -/** \returns an expression of the identity matrix (not necessarily square). - * - * The parameters \a nbRows and \a nbCols are the number of rows and of columns of - * the returned matrix. Must be compatible with this MatrixBase type. - * - * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, - * it is redundant to pass \a rows and \a cols as arguments, so Identity() should be used - * instead. - * - * Example: \include MatrixBase_identity_int_int.cpp - * Output: \verbinclude MatrixBase_identity_int_int.out - * - * \sa Identity(), setIdentity(), isIdentity() - */ -template -EIGEN_STRONG_INLINE const typename MatrixBase::IdentityReturnType -MatrixBase::Identity(Index nbRows, Index nbCols) -{ - return DenseBase::NullaryExpr(nbRows, nbCols, internal::scalar_identity_op()); -} - -/** \returns an expression of the identity matrix (not necessarily square). - * - * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you - * need to use the variant taking size arguments. - * - * Example: \include MatrixBase_identity.cpp - * Output: \verbinclude MatrixBase_identity.out - * - * \sa Identity(Index,Index), setIdentity(), isIdentity() - */ -template -EIGEN_STRONG_INLINE const typename MatrixBase::IdentityReturnType -MatrixBase::Identity() -{ - EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) - return MatrixBase::NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_identity_op()); -} - -/** \returns true if *this is approximately equal to the identity matrix - * (not necessarily square), - * within the precision given by \a prec. - * - * Example: \include MatrixBase_isIdentity.cpp - * Output: \verbinclude MatrixBase_isIdentity.out - * - * \sa class CwiseNullaryOp, Identity(), Identity(Index,Index), setIdentity() - */ -template -bool MatrixBase::isIdentity -(const RealScalar& prec) const -{ - for(Index j = 0; j < cols(); ++j) - { - for(Index i = 0; i < rows(); ++i) - { - if(i == j) - { - if(!internal::isApprox(this->coeff(i, j), static_cast(1), prec)) - return false; - } - else - { - if(!internal::isMuchSmallerThan(this->coeff(i, j), static_cast(1), prec)) - return false; - } - } - } - return true; -} - -namespace internal { - -template=16)> -struct setIdentity_impl -{ - static EIGEN_STRONG_INLINE Derived& run(Derived& m) - { - return m = Derived::Identity(m.rows(), m.cols()); - } -}; - -template -struct setIdentity_impl -{ - typedef typename Derived::Index Index; - static EIGEN_STRONG_INLINE Derived& run(Derived& m) - { - m.setZero(); - const Index size = (std::min)(m.rows(), m.cols()); - for(Index i = 0; i < size; ++i) m.coeffRef(i,i) = typename Derived::Scalar(1); - return m; - } -}; - -} // end namespace internal - -/** Writes the identity expression (not necessarily square) into *this. - * - * Example: \include MatrixBase_setIdentity.cpp - * Output: \verbinclude MatrixBase_setIdentity.out - * - * \sa class CwiseNullaryOp, Identity(), Identity(Index,Index), isIdentity() - */ -template -EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity() -{ - return internal::setIdentity_impl::run(derived()); -} - -/** \brief Resizes to the given size, and writes the identity expression (not necessarily square) into *this. - * - * \param nbRows the new number of rows - * \param nbCols the new number of columns - * - * Example: \include Matrix_setIdentity_int_int.cpp - * Output: \verbinclude Matrix_setIdentity_int_int.out - * - * \sa MatrixBase::setIdentity(), class CwiseNullaryOp, MatrixBase::Identity() - */ -template -EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity(Index nbRows, Index nbCols) -{ - derived().resize(nbRows, nbCols); - return setIdentity(); -} - -/** \returns an expression of the i-th unit (basis) vector. - * - * \only_for_vectors - * - * \sa MatrixBase::Unit(Index), MatrixBase::UnitX(), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() - */ -template -EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::Unit(Index newSize, Index i) -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return BasisReturnType(SquareMatrixType::Identity(newSize,newSize), i); -} - -/** \returns an expression of the i-th unit (basis) vector. - * - * \only_for_vectors - * - * This variant is for fixed-size vector only. - * - * \sa MatrixBase::Unit(Index,Index), MatrixBase::UnitX(), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() - */ -template -EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::Unit(Index i) -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return BasisReturnType(SquareMatrixType::Identity(),i); -} - -/** \returns an expression of the X axis unit vector (1{,0}^*) - * - * \only_for_vectors - * - * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() - */ -template -EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitX() -{ return Derived::Unit(0); } - -/** \returns an expression of the Y axis unit vector (0,1{,0}^*) - * - * \only_for_vectors - * - * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() - */ -template -EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitY() -{ return Derived::Unit(1); } - -/** \returns an expression of the Z axis unit vector (0,0,1{,0}^*) - * - * \only_for_vectors - * - * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() - */ -template -EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitZ() -{ return Derived::Unit(2); } - -/** \returns an expression of the W axis unit vector (0,0,0,1) - * - * \only_for_vectors - * - * \sa MatrixBase::Unit(Index,Index), MatrixBase::Unit(Index), MatrixBase::UnitY(), MatrixBase::UnitZ(), MatrixBase::UnitW() - */ -template -EIGEN_STRONG_INLINE const typename MatrixBase::BasisReturnType MatrixBase::UnitW() -{ return Derived::Unit(3); } - -} // end namespace Eigen - -#endif // EIGEN_CWISE_NULLARY_OP_H diff --git a/splinter/src/Core/CwiseUnaryOp.h b/splinter/src/Core/CwiseUnaryOp.h deleted file mode 100644 index f7ee60e987..0000000000 --- a/splinter/src/Core/CwiseUnaryOp.h +++ /dev/null @@ -1,126 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2010 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_CWISE_UNARY_OP_H -#define EIGEN_CWISE_UNARY_OP_H - -namespace Eigen { - -/** \class CwiseUnaryOp - * \ingroup Core_Module - * - * \brief Generic expression where a coefficient-wise unary operator is applied to an expression - * - * \param UnaryOp template functor implementing the operator - * \param XprType the type of the expression to which we are applying the unary operator - * - * This class represents an expression where a unary operator is applied to an expression. - * It is the return type of all operations taking exactly 1 input expression, regardless of the - * presence of other inputs such as scalars. For example, the operator* in the expression 3*matrix - * is considered unary, because only the right-hand side is an expression, and its - * return type is a specialization of CwiseUnaryOp. - * - * Most of the time, this is the only way that it is used, so you typically don't have to name - * CwiseUnaryOp types explicitly. - * - * \sa MatrixBase::unaryExpr(const CustomUnaryOp &) const, class CwiseBinaryOp, class CwiseNullaryOp - */ - -namespace internal { -template -struct traits > - : traits -{ - typedef typename result_of< - UnaryOp(typename XprType::Scalar) - >::type Scalar; - typedef typename XprType::Nested XprTypeNested; - typedef typename remove_reference::type _XprTypeNested; - enum { - Flags = _XprTypeNested::Flags & ( - HereditaryBits | LinearAccessBit | AlignedBit - | (functor_traits::PacketAccess ? PacketAccessBit : 0)), - CoeffReadCost = EIGEN_ADD_COST(_XprTypeNested::CoeffReadCost, functor_traits::Cost) - }; -}; -} - -template -class CwiseUnaryOpImpl; - -template -class CwiseUnaryOp : internal::no_assignment_operator, - public CwiseUnaryOpImpl::StorageKind> -{ - public: - - typedef typename CwiseUnaryOpImpl::StorageKind>::Base Base; - EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryOp) - - inline CwiseUnaryOp(const XprType& xpr, const UnaryOp& func = UnaryOp()) - : m_xpr(xpr), m_functor(func) {} - - EIGEN_STRONG_INLINE Index rows() const { return m_xpr.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return m_xpr.cols(); } - - /** \returns the functor representing the unary operation */ - const UnaryOp& functor() const { return m_functor; } - - /** \returns the nested expression */ - const typename internal::remove_all::type& - nestedExpression() const { return m_xpr; } - - /** \returns the nested expression */ - typename internal::remove_all::type& - nestedExpression() { return m_xpr.const_cast_derived(); } - - protected: - typename XprType::Nested m_xpr; - const UnaryOp m_functor; -}; - -// This is the generic implementation for dense storage. -// It can be used for any expression types implementing the dense concept. -template -class CwiseUnaryOpImpl - : public internal::dense_xpr_base >::type -{ - public: - - typedef CwiseUnaryOp Derived; - typedef typename internal::dense_xpr_base >::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(Derived) - - EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const - { - return derived().functor()(derived().nestedExpression().coeff(rowId, colId)); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const - { - return derived().functor().packetOp(derived().nestedExpression().template packet(rowId, colId)); - } - - EIGEN_STRONG_INLINE const Scalar coeff(Index index) const - { - return derived().functor()(derived().nestedExpression().coeff(index)); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index index) const - { - return derived().functor().packetOp(derived().nestedExpression().template packet(index)); - } -}; - -} // end namespace Eigen - -#endif // EIGEN_CWISE_UNARY_OP_H diff --git a/splinter/src/Core/CwiseUnaryView.h b/splinter/src/Core/CwiseUnaryView.h deleted file mode 100644 index f3b2ffeb6f..0000000000 --- a/splinter/src/Core/CwiseUnaryView.h +++ /dev/null @@ -1,139 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_CWISE_UNARY_VIEW_H -#define EIGEN_CWISE_UNARY_VIEW_H - -namespace Eigen { - -/** \class CwiseUnaryView - * \ingroup Core_Module - * - * \brief Generic lvalue expression of a coefficient-wise unary operator of a matrix or a vector - * - * \param ViewOp template functor implementing the view - * \param MatrixType the type of the matrix we are applying the unary operator - * - * This class represents a lvalue expression of a generic unary view operator of a matrix or a vector. - * It is the return type of real() and imag(), and most of the time this is the only way it is used. - * - * \sa MatrixBase::unaryViewExpr(const CustomUnaryOp &) const, class CwiseUnaryOp - */ - -namespace internal { -template -struct traits > - : traits -{ - typedef typename result_of< - ViewOp(typename traits::Scalar) - >::type Scalar; - typedef typename MatrixType::Nested MatrixTypeNested; - typedef typename remove_all::type _MatrixTypeNested; - enum { - Flags = (traits<_MatrixTypeNested>::Flags & (HereditaryBits | LvalueBit | LinearAccessBit | DirectAccessBit)), - CoeffReadCost = EIGEN_ADD_COST(traits<_MatrixTypeNested>::CoeffReadCost, functor_traits::Cost), - MatrixTypeInnerStride = inner_stride_at_compile_time::ret, - // need to cast the sizeof's from size_t to int explicitly, otherwise: - // "error: no integral type can represent all of the enumerator values - InnerStrideAtCompileTime = MatrixTypeInnerStride == Dynamic - ? int(Dynamic) - : int(MatrixTypeInnerStride) * int(sizeof(typename traits::Scalar) / sizeof(Scalar)), - OuterStrideAtCompileTime = outer_stride_at_compile_time::ret == Dynamic - ? int(Dynamic) - : outer_stride_at_compile_time::ret * int(sizeof(typename traits::Scalar) / sizeof(Scalar)) - }; -}; -} - -template -class CwiseUnaryViewImpl; - -template -class CwiseUnaryView : public CwiseUnaryViewImpl::StorageKind> -{ - public: - - typedef typename CwiseUnaryViewImpl::StorageKind>::Base Base; - EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryView) - - inline CwiseUnaryView(const MatrixType& mat, const ViewOp& func = ViewOp()) - : m_matrix(mat), m_functor(func) {} - - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryView) - - EIGEN_STRONG_INLINE Index rows() const { return m_matrix.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return m_matrix.cols(); } - - /** \returns the functor representing unary operation */ - const ViewOp& functor() const { return m_functor; } - - /** \returns the nested expression */ - const typename internal::remove_all::type& - nestedExpression() const { return m_matrix; } - - /** \returns the nested expression */ - typename internal::remove_all::type& - nestedExpression() { return m_matrix.const_cast_derived(); } - - protected: - // FIXME changed from MatrixType::Nested because of a weird compilation error with sun CC - typename internal::nested::type m_matrix; - ViewOp m_functor; -}; - -template -class CwiseUnaryViewImpl - : public internal::dense_xpr_base< CwiseUnaryView >::type -{ - public: - - typedef CwiseUnaryView Derived; - typedef typename internal::dense_xpr_base< CwiseUnaryView >::type Base; - - EIGEN_DENSE_PUBLIC_INTERFACE(Derived) - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryViewImpl) - - inline Scalar* data() { return &coeffRef(0); } - inline const Scalar* data() const { return &coeff(0); } - - inline Index innerStride() const - { - return derived().nestedExpression().innerStride() * sizeof(typename internal::traits::Scalar) / sizeof(Scalar); - } - - inline Index outerStride() const - { - return derived().nestedExpression().outerStride() * sizeof(typename internal::traits::Scalar) / sizeof(Scalar); - } - - EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const - { - return derived().functor()(derived().nestedExpression().coeff(row, col)); - } - - EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const - { - return derived().functor()(derived().nestedExpression().coeff(index)); - } - - EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) - { - return derived().functor()(const_cast_derived().nestedExpression().coeffRef(row, col)); - } - - EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) - { - return derived().functor()(const_cast_derived().nestedExpression().coeffRef(index)); - } -}; - -} // end namespace Eigen - -#endif // EIGEN_CWISE_UNARY_VIEW_H diff --git a/splinter/src/Core/DenseBase.h b/splinter/src/Core/DenseBase.h deleted file mode 100644 index 4b371b075b..0000000000 --- a/splinter/src/Core/DenseBase.h +++ /dev/null @@ -1,521 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2007-2010 Benoit Jacob -// Copyright (C) 2008-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_DENSEBASE_H -#define EIGEN_DENSEBASE_H - -namespace Eigen { - -namespace internal { - -// The index type defined by EIGEN_DEFAULT_DENSE_INDEX_TYPE must be a signed type. -// This dummy function simply aims at checking that at compile time. -static inline void check_DenseIndex_is_signed() { - EIGEN_STATIC_ASSERT(NumTraits::IsSigned,THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE); -} - -} // end namespace internal - -/** \class DenseBase - * \ingroup Core_Module - * - * \brief Base class for all dense matrices, vectors, and arrays - * - * This class is the base that is inherited by all dense objects (matrix, vector, arrays, - * and related expression types). The common Eigen API for dense objects is contained in this class. - * - * \tparam Derived is the derived type, e.g., a matrix type or an expression. - * - * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_DENSEBASE_PLUGIN. - * - * \sa \ref TopicClassHierarchy - */ -template class DenseBase -#ifndef EIGEN_PARSED_BY_DOXYGEN - : public internal::special_scalar_op_base::Scalar, - typename NumTraits::Scalar>::Real, - DenseCoeffsBase > -#else - : public DenseCoeffsBase -#endif // not EIGEN_PARSED_BY_DOXYGEN -{ - public: - - class InnerIterator; - - typedef typename internal::traits::StorageKind StorageKind; - - /** \brief The type of indices - * \details To change this, \c \#define the preprocessor symbol \c EIGEN_DEFAULT_DENSE_INDEX_TYPE. - * \sa \ref TopicPreprocessorDirectives. - */ - typedef typename internal::traits::Index Index; - - typedef typename internal::traits::Scalar Scalar; - typedef typename internal::packet_traits::type PacketScalar; - typedef typename NumTraits::Real RealScalar; - typedef internal::special_scalar_op_base > Base; - - using Base::operator*; - using Base::derived; - using Base::const_cast_derived; - using Base::rows; - using Base::cols; - using Base::size; - using Base::rowIndexByOuterInner; - using Base::colIndexByOuterInner; - using Base::coeff; - using Base::coeffByOuterInner; - using Base::packet; - using Base::packetByOuterInner; - using Base::writePacket; - using Base::writePacketByOuterInner; - using Base::coeffRef; - using Base::coeffRefByOuterInner; - using Base::copyCoeff; - using Base::copyCoeffByOuterInner; - using Base::copyPacket; - using Base::copyPacketByOuterInner; - using Base::operator(); - using Base::operator[]; - using Base::x; - using Base::y; - using Base::z; - using Base::w; - using Base::stride; - using Base::innerStride; - using Base::outerStride; - using Base::rowStride; - using Base::colStride; - typedef typename Base::CoeffReturnType CoeffReturnType; - - enum { - - RowsAtCompileTime = internal::traits::RowsAtCompileTime, - /**< The number of rows at compile-time. This is just a copy of the value provided - * by the \a Derived type. If a value is not known at compile-time, - * it is set to the \a Dynamic constant. - * \sa MatrixBase::rows(), MatrixBase::cols(), ColsAtCompileTime, SizeAtCompileTime */ - - ColsAtCompileTime = internal::traits::ColsAtCompileTime, - /**< The number of columns at compile-time. This is just a copy of the value provided - * by the \a Derived type. If a value is not known at compile-time, - * it is set to the \a Dynamic constant. - * \sa MatrixBase::rows(), MatrixBase::cols(), RowsAtCompileTime, SizeAtCompileTime */ - - - SizeAtCompileTime = (internal::size_at_compile_time::RowsAtCompileTime, - internal::traits::ColsAtCompileTime>::ret), - /**< This is equal to the number of coefficients, i.e. the number of - * rows times the number of columns, or to \a Dynamic if this is not - * known at compile-time. \sa RowsAtCompileTime, ColsAtCompileTime */ - - MaxRowsAtCompileTime = internal::traits::MaxRowsAtCompileTime, - /**< This value is equal to the maximum possible number of rows that this expression - * might have. If this expression might have an arbitrarily high number of rows, - * this value is set to \a Dynamic. - * - * This value is useful to know when evaluating an expression, in order to determine - * whether it is possible to avoid doing a dynamic memory allocation. - * - * \sa RowsAtCompileTime, MaxColsAtCompileTime, MaxSizeAtCompileTime - */ - - MaxColsAtCompileTime = internal::traits::MaxColsAtCompileTime, - /**< This value is equal to the maximum possible number of columns that this expression - * might have. If this expression might have an arbitrarily high number of columns, - * this value is set to \a Dynamic. - * - * This value is useful to know when evaluating an expression, in order to determine - * whether it is possible to avoid doing a dynamic memory allocation. - * - * \sa ColsAtCompileTime, MaxRowsAtCompileTime, MaxSizeAtCompileTime - */ - - MaxSizeAtCompileTime = (internal::size_at_compile_time::MaxRowsAtCompileTime, - internal::traits::MaxColsAtCompileTime>::ret), - /**< This value is equal to the maximum possible number of coefficients that this expression - * might have. If this expression might have an arbitrarily high number of coefficients, - * this value is set to \a Dynamic. - * - * This value is useful to know when evaluating an expression, in order to determine - * whether it is possible to avoid doing a dynamic memory allocation. - * - * \sa SizeAtCompileTime, MaxRowsAtCompileTime, MaxColsAtCompileTime - */ - - IsVectorAtCompileTime = internal::traits::MaxRowsAtCompileTime == 1 - || internal::traits::MaxColsAtCompileTime == 1, - /**< This is set to true if either the number of rows or the number of - * columns is known at compile-time to be equal to 1. Indeed, in that case, - * we are dealing with a column-vector (if there is only one column) or with - * a row-vector (if there is only one row). */ - - Flags = internal::traits::Flags, - /**< This stores expression \ref flags flags which may or may not be inherited by new expressions - * constructed from this one. See the \ref flags "list of flags". - */ - - IsRowMajor = int(Flags) & RowMajorBit, /**< True if this expression has row-major storage order. */ - - InnerSizeAtCompileTime = int(IsVectorAtCompileTime) ? int(SizeAtCompileTime) - : int(IsRowMajor) ? int(ColsAtCompileTime) : int(RowsAtCompileTime), - - CoeffReadCost = internal::traits::CoeffReadCost, - /**< This is a rough measure of how expensive it is to read one coefficient from - * this expression. - */ - - InnerStrideAtCompileTime = internal::inner_stride_at_compile_time::ret, - OuterStrideAtCompileTime = internal::outer_stride_at_compile_time::ret - }; - - enum { ThisConstantIsPrivateInPlainObjectBase }; - - /** \returns the number of nonzero coefficients which is in practice the number - * of stored coefficients. */ - inline Index nonZeros() const { return size(); } - - /** \returns the outer size. - * - * \note For a vector, this returns just 1. For a matrix (non-vector), this is the major dimension - * with respect to the \ref TopicStorageOrders "storage order", i.e., the number of columns for a - * column-major matrix, and the number of rows for a row-major matrix. */ - Index outerSize() const - { - return IsVectorAtCompileTime ? 1 - : int(IsRowMajor) ? this->rows() : this->cols(); - } - - /** \returns the inner size. - * - * \note For a vector, this is just the size. For a matrix (non-vector), this is the minor dimension - * with respect to the \ref TopicStorageOrders "storage order", i.e., the number of rows for a - * column-major matrix, and the number of columns for a row-major matrix. */ - Index innerSize() const - { - return IsVectorAtCompileTime ? this->size() - : int(IsRowMajor) ? this->cols() : this->rows(); - } - - /** Only plain matrices/arrays, not expressions, may be resized; therefore the only useful resize methods are - * Matrix::resize() and Array::resize(). The present method only asserts that the new size equals the old size, and does - * nothing else. - */ - void resize(Index newSize) - { - EIGEN_ONLY_USED_FOR_DEBUG(newSize); - eigen_assert(newSize == this->size() - && "DenseBase::resize() does not actually allow to resize."); - } - /** Only plain matrices/arrays, not expressions, may be resized; therefore the only useful resize methods are - * Matrix::resize() and Array::resize(). The present method only asserts that the new size equals the old size, and does - * nothing else. - */ - void resize(Index nbRows, Index nbCols) - { - EIGEN_ONLY_USED_FOR_DEBUG(nbRows); - EIGEN_ONLY_USED_FOR_DEBUG(nbCols); - eigen_assert(nbRows == this->rows() && nbCols == this->cols() - && "DenseBase::resize() does not actually allow to resize."); - } - -#ifndef EIGEN_PARSED_BY_DOXYGEN - - /** \internal Represents a matrix with all coefficients equal to one another*/ - typedef CwiseNullaryOp,Derived> ConstantReturnType; - /** \internal Represents a vector with linearly spaced coefficients that allows sequential access only. */ - typedef CwiseNullaryOp,Derived> SequentialLinSpacedReturnType; - /** \internal Represents a vector with linearly spaced coefficients that allows random access. */ - typedef CwiseNullaryOp,Derived> RandomAccessLinSpacedReturnType; - /** \internal the return type of MatrixBase::eigenvalues() */ - typedef Matrix::Scalar>::Real, internal::traits::ColsAtCompileTime, 1> EigenvaluesReturnType; - -#endif // not EIGEN_PARSED_BY_DOXYGEN - - /** Copies \a other into *this. \returns a reference to *this. */ - template - Derived& operator=(const DenseBase& other); - - /** Special case of the template operator=, in order to prevent the compiler - * from generating a default operator= (issue hit with g++ 4.1) - */ - Derived& operator=(const DenseBase& other); - - template - Derived& operator=(const EigenBase &other); - - template - Derived& operator+=(const EigenBase &other); - - template - Derived& operator-=(const EigenBase &other); - - template - Derived& operator=(const ReturnByValue& func); - - /** \internal Copies \a other into *this without evaluating other. \returns a reference to *this. */ - template - Derived& lazyAssign(const DenseBase& other); - - /** \internal Evaluates \a other into *this. \returns a reference to *this. */ - template - Derived& lazyAssign(const ReturnByValue& other); - - CommaInitializer operator<< (const Scalar& s); - - template - const Flagged flagged() const; - - template - CommaInitializer operator<< (const DenseBase& other); - - Eigen::Transpose transpose(); - typedef typename internal::add_const >::type ConstTransposeReturnType; - ConstTransposeReturnType transpose() const; - void transposeInPlace(); -#ifndef EIGEN_NO_DEBUG - protected: - template - void checkTransposeAliasing(const OtherDerived& other) const; - public: -#endif - - - static const ConstantReturnType - Constant(Index rows, Index cols, const Scalar& value); - static const ConstantReturnType - Constant(Index size, const Scalar& value); - static const ConstantReturnType - Constant(const Scalar& value); - - static const SequentialLinSpacedReturnType - LinSpaced(Sequential_t, Index size, const Scalar& low, const Scalar& high); - static const RandomAccessLinSpacedReturnType - LinSpaced(Index size, const Scalar& low, const Scalar& high); - static const SequentialLinSpacedReturnType - LinSpaced(Sequential_t, const Scalar& low, const Scalar& high); - static const RandomAccessLinSpacedReturnType - LinSpaced(const Scalar& low, const Scalar& high); - - template - static const CwiseNullaryOp - NullaryExpr(Index rows, Index cols, const CustomNullaryOp& func); - template - static const CwiseNullaryOp - NullaryExpr(Index size, const CustomNullaryOp& func); - template - static const CwiseNullaryOp - NullaryExpr(const CustomNullaryOp& func); - - static const ConstantReturnType Zero(Index rows, Index cols); - static const ConstantReturnType Zero(Index size); - static const ConstantReturnType Zero(); - static const ConstantReturnType Ones(Index rows, Index cols); - static const ConstantReturnType Ones(Index size); - static const ConstantReturnType Ones(); - - void fill(const Scalar& value); - Derived& setConstant(const Scalar& value); - Derived& setLinSpaced(Index size, const Scalar& low, const Scalar& high); - Derived& setLinSpaced(const Scalar& low, const Scalar& high); - Derived& setZero(); - Derived& setOnes(); - Derived& setRandom(); - - template - bool isApprox(const DenseBase& other, - const RealScalar& prec = NumTraits::dummy_precision()) const; - bool isMuchSmallerThan(const RealScalar& other, - const RealScalar& prec = NumTraits::dummy_precision()) const; - template - bool isMuchSmallerThan(const DenseBase& other, - const RealScalar& prec = NumTraits::dummy_precision()) const; - - bool isApproxToConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; - bool isConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; - bool isZero(const RealScalar& prec = NumTraits::dummy_precision()) const; - bool isOnes(const RealScalar& prec = NumTraits::dummy_precision()) const; - - inline bool hasNaN() const; - inline bool allFinite() const; - - inline Derived& operator*=(const Scalar& other); - inline Derived& operator/=(const Scalar& other); - - typedef typename internal::add_const_on_value_type::type>::type EvalReturnType; - /** \returns the matrix or vector obtained by evaluating this expression. - * - * Notice that in the case of a plain matrix or vector (not an expression) this function just returns - * a const reference, in order to avoid a useless copy. - */ - EIGEN_STRONG_INLINE EvalReturnType eval() const - { - // Even though MSVC does not honor strong inlining when the return type - // is a dynamic matrix, we desperately need strong inlining for fixed - // size types on MSVC. - return typename internal::eval::type(derived()); - } - - /** swaps *this with the expression \a other. - * - */ - template - void swap(const DenseBase& other, - int = OtherDerived::ThisConstantIsPrivateInPlainObjectBase) - { - SwapWrapper(derived()).lazyAssign(other.derived()); - } - - /** swaps *this with the matrix or array \a other. - * - */ - template - void swap(PlainObjectBase& other) - { - SwapWrapper(derived()).lazyAssign(other.derived()); - } - - - inline const NestByValue nestByValue() const; - inline const ForceAlignedAccess forceAlignedAccess() const; - inline ForceAlignedAccess forceAlignedAccess(); - template inline const typename internal::conditional,Derived&>::type forceAlignedAccessIf() const; - template inline typename internal::conditional,Derived&>::type forceAlignedAccessIf(); - - Scalar sum() const; - Scalar mean() const; - Scalar trace() const; - - Scalar prod() const; - - typename internal::traits::Scalar minCoeff() const; - typename internal::traits::Scalar maxCoeff() const; - - template - typename internal::traits::Scalar minCoeff(IndexType* row, IndexType* col) const; - template - typename internal::traits::Scalar maxCoeff(IndexType* row, IndexType* col) const; - template - typename internal::traits::Scalar minCoeff(IndexType* index) const; - template - typename internal::traits::Scalar maxCoeff(IndexType* index) const; - - template - typename internal::result_of::Scalar)>::type - redux(const BinaryOp& func) const; - - template - void visit(Visitor& func) const; - - inline const WithFormat format(const IOFormat& fmt) const; - - /** \returns the unique coefficient of a 1x1 expression */ - CoeffReturnType value() const - { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - return derived().coeff(0,0); - } - - bool all(void) const; - bool any(void) const; - Index count() const; - - typedef VectorwiseOp RowwiseReturnType; - typedef const VectorwiseOp ConstRowwiseReturnType; - typedef VectorwiseOp ColwiseReturnType; - typedef const VectorwiseOp ConstColwiseReturnType; - - ConstRowwiseReturnType rowwise() const; - RowwiseReturnType rowwise(); - ConstColwiseReturnType colwise() const; - ColwiseReturnType colwise(); - - static const CwiseNullaryOp,Derived> Random(Index rows, Index cols); - static const CwiseNullaryOp,Derived> Random(Index size); - static const CwiseNullaryOp,Derived> Random(); - - template - const Select - select(const DenseBase& thenMatrix, - const DenseBase& elseMatrix) const; - - template - inline const Select - select(const DenseBase& thenMatrix, const typename ThenDerived::Scalar& elseScalar) const; - - template - inline const Select - select(const typename ElseDerived::Scalar& thenScalar, const DenseBase& elseMatrix) const; - - template RealScalar lpNorm() const; - - template - inline const Replicate replicate() const; - - typedef Replicate ReplicateReturnType; - inline const ReplicateReturnType replicate(Index rowFacor,Index colFactor) const; - - typedef Reverse ReverseReturnType; - typedef const Reverse ConstReverseReturnType; - ReverseReturnType reverse(); - ConstReverseReturnType reverse() const; - void reverseInPlace(); - -#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::DenseBase -# include "../plugins/BlockMethods.h" -# ifdef EIGEN_DENSEBASE_PLUGIN -# include EIGEN_DENSEBASE_PLUGIN -# endif -#undef EIGEN_CURRENT_STORAGE_BASE_CLASS - -#ifdef EIGEN2_SUPPORT - - Block corner(CornerType type, Index cRows, Index cCols); - const Block corner(CornerType type, Index cRows, Index cCols) const; - template - Block corner(CornerType type); - template - const Block corner(CornerType type) const; - -#endif // EIGEN2_SUPPORT - - - // disable the use of evalTo for dense objects with a nice compilation error - template inline void evalTo(Dest& ) const - { - EIGEN_STATIC_ASSERT((internal::is_same::value),THE_EVAL_EVALTO_FUNCTION_SHOULD_NEVER_BE_CALLED_FOR_DENSE_OBJECTS); - } - - protected: - /** Default constructor. Do nothing. */ - DenseBase() - { - /* Just checks for self-consistency of the flags. - * Only do it when debugging Eigen, as this borders on paranoiac and could slow compilation down - */ -#ifdef EIGEN_INTERNAL_DEBUGGING - EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, int(IsRowMajor)) - && EIGEN_IMPLIES(MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1, int(!IsRowMajor))), - INVALID_STORAGE_ORDER_FOR_THIS_VECTOR_EXPRESSION) -#endif - } - - private: - explicit DenseBase(int); - DenseBase(int,int); - template explicit DenseBase(const DenseBase&); -}; - -} // end namespace Eigen - -#endif // EIGEN_DENSEBASE_H diff --git a/splinter/src/Core/DenseCoeffsBase.h b/splinter/src/Core/DenseCoeffsBase.h deleted file mode 100644 index 3c890f2159..0000000000 --- a/splinter/src/Core/DenseCoeffsBase.h +++ /dev/null @@ -1,754 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2010 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_DENSECOEFFSBASE_H -#define EIGEN_DENSECOEFFSBASE_H - -namespace Eigen { - -namespace internal { -template struct add_const_on_value_type_if_arithmetic -{ - typedef typename conditional::value, T, typename add_const_on_value_type::type>::type type; -}; -} - -/** \brief Base class providing read-only coefficient access to matrices and arrays. - * \ingroup Core_Module - * \tparam Derived Type of the derived class - * \tparam #ReadOnlyAccessors Constant indicating read-only access - * - * This class defines the \c operator() \c const function and friends, which can be used to read specific - * entries of a matrix or array. - * - * \sa DenseCoeffsBase, DenseCoeffsBase, - * \ref TopicClassHierarchy - */ -template -class DenseCoeffsBase : public EigenBase -{ - public: - typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; - typedef typename internal::traits::Scalar Scalar; - typedef typename internal::packet_traits::type PacketScalar; - - // Explanation for this CoeffReturnType typedef. - // - This is the return type of the coeff() method. - // - The LvalueBit means exactly that we can offer a coeffRef() method, which means exactly that we can get references - // to coeffs, which means exactly that we can have coeff() return a const reference (as opposed to returning a value). - // - The is_artihmetic check is required since "const int", "const double", etc. will cause warnings on some systems - // while the declaration of "const T", where T is a non arithmetic type does not. Always returning "const Scalar&" is - // not possible, since the underlying expressions might not offer a valid address the reference could be referring to. - typedef typename internal::conditional::Flags&LvalueBit), - const Scalar&, - typename internal::conditional::value, Scalar, const Scalar>::type - >::type CoeffReturnType; - - typedef typename internal::add_const_on_value_type_if_arithmetic< - typename internal::packet_traits::type - >::type PacketReturnType; - - typedef EigenBase Base; - using Base::rows; - using Base::cols; - using Base::size; - using Base::derived; - - EIGEN_STRONG_INLINE Index rowIndexByOuterInner(Index outer, Index inner) const - { - return int(Derived::RowsAtCompileTime) == 1 ? 0 - : int(Derived::ColsAtCompileTime) == 1 ? inner - : int(Derived::Flags)&RowMajorBit ? outer - : inner; - } - - EIGEN_STRONG_INLINE Index colIndexByOuterInner(Index outer, Index inner) const - { - return int(Derived::ColsAtCompileTime) == 1 ? 0 - : int(Derived::RowsAtCompileTime) == 1 ? inner - : int(Derived::Flags)&RowMajorBit ? inner - : outer; - } - - /** Short version: don't use this function, use - * \link operator()(Index,Index) const \endlink instead. - * - * Long version: this function is similar to - * \link operator()(Index,Index) const \endlink, but without the assertion. - * Use this for limiting the performance cost of debugging code when doing - * repeated coefficient access. Only use this when it is guaranteed that the - * parameters \a row and \a col are in range. - * - * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this - * function equivalent to \link operator()(Index,Index) const \endlink. - * - * \sa operator()(Index,Index) const, coeffRef(Index,Index), coeff(Index) const - */ - EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const - { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - return derived().coeff(row, col); - } - - EIGEN_STRONG_INLINE CoeffReturnType coeffByOuterInner(Index outer, Index inner) const - { - return coeff(rowIndexByOuterInner(outer, inner), - colIndexByOuterInner(outer, inner)); - } - - /** \returns the coefficient at given the given row and column. - * - * \sa operator()(Index,Index), operator[](Index) - */ - EIGEN_STRONG_INLINE CoeffReturnType operator()(Index row, Index col) const - { - eigen_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - return derived().coeff(row, col); - } - - /** Short version: don't use this function, use - * \link operator[](Index) const \endlink instead. - * - * Long version: this function is similar to - * \link operator[](Index) const \endlink, but without the assertion. - * Use this for limiting the performance cost of debugging code when doing - * repeated coefficient access. Only use this when it is guaranteed that the - * parameter \a index is in range. - * - * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this - * function equivalent to \link operator[](Index) const \endlink. - * - * \sa operator[](Index) const, coeffRef(Index), coeff(Index,Index) const - */ - - EIGEN_STRONG_INLINE CoeffReturnType - coeff(Index index) const - { - eigen_internal_assert(index >= 0 && index < size()); - return derived().coeff(index); - } - - - /** \returns the coefficient at given index. - * - * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. - * - * \sa operator[](Index), operator()(Index,Index) const, x() const, y() const, - * z() const, w() const - */ - - EIGEN_STRONG_INLINE CoeffReturnType - operator[](Index index) const - { - #ifndef EIGEN2_SUPPORT - EIGEN_STATIC_ASSERT(Derived::IsVectorAtCompileTime, - THE_BRACKET_OPERATOR_IS_ONLY_FOR_VECTORS__USE_THE_PARENTHESIS_OPERATOR_INSTEAD) - #endif - eigen_assert(index >= 0 && index < size()); - return derived().coeff(index); - } - - /** \returns the coefficient at given index. - * - * This is synonymous to operator[](Index) const. - * - * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. - * - * \sa operator[](Index), operator()(Index,Index) const, x() const, y() const, - * z() const, w() const - */ - - EIGEN_STRONG_INLINE CoeffReturnType - operator()(Index index) const - { - eigen_assert(index >= 0 && index < size()); - return derived().coeff(index); - } - - /** equivalent to operator[](0). */ - - EIGEN_STRONG_INLINE CoeffReturnType - x() const { return (*this)[0]; } - - /** equivalent to operator[](1). */ - - EIGEN_STRONG_INLINE CoeffReturnType - y() const { return (*this)[1]; } - - /** equivalent to operator[](2). */ - - EIGEN_STRONG_INLINE CoeffReturnType - z() const { return (*this)[2]; } - - /** equivalent to operator[](3). */ - - EIGEN_STRONG_INLINE CoeffReturnType - w() const { return (*this)[3]; } - - /** \internal - * \returns the packet of coefficients starting at the given row and column. It is your responsibility - * to ensure that a packet really starts there. This method is only available on expressions having the - * PacketAccessBit. - * - * The \a LoadMode parameter may have the value \a #Aligned or \a #Unaligned. Its effect is to select - * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets - * starting at an address which is a multiple of the packet size. - */ - - template - EIGEN_STRONG_INLINE PacketReturnType packet(Index row, Index col) const - { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - return derived().template packet(row,col); - } - - - /** \internal */ - template - EIGEN_STRONG_INLINE PacketReturnType packetByOuterInner(Index outer, Index inner) const - { - return packet(rowIndexByOuterInner(outer, inner), - colIndexByOuterInner(outer, inner)); - } - - /** \internal - * \returns the packet of coefficients starting at the given index. It is your responsibility - * to ensure that a packet really starts there. This method is only available on expressions having the - * PacketAccessBit and the LinearAccessBit. - * - * The \a LoadMode parameter may have the value \a #Aligned or \a #Unaligned. Its effect is to select - * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets - * starting at an address which is a multiple of the packet size. - */ - - template - EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const - { - eigen_internal_assert(index >= 0 && index < size()); - return derived().template packet(index); - } - - protected: - // explanation: DenseBase is doing "using ..." on the methods from DenseCoeffsBase. - // But some methods are only available in the DirectAccess case. - // So we add dummy methods here with these names, so that "using... " doesn't fail. - // It's not private so that the child class DenseBase can access them, and it's not public - // either since it's an implementation detail, so has to be protected. - void coeffRef(); - void coeffRefByOuterInner(); - void writePacket(); - void writePacketByOuterInner(); - void copyCoeff(); - void copyCoeffByOuterInner(); - void copyPacket(); - void copyPacketByOuterInner(); - void stride(); - void innerStride(); - void outerStride(); - void rowStride(); - void colStride(); -}; - -/** \brief Base class providing read/write coefficient access to matrices and arrays. - * \ingroup Core_Module - * \tparam Derived Type of the derived class - * \tparam #WriteAccessors Constant indicating read/write access - * - * This class defines the non-const \c operator() function and friends, which can be used to write specific - * entries of a matrix or array. This class inherits DenseCoeffsBase which - * defines the const variant for reading specific entries. - * - * \sa DenseCoeffsBase, \ref TopicClassHierarchy - */ -template -class DenseCoeffsBase : public DenseCoeffsBase -{ - public: - - typedef DenseCoeffsBase Base; - - typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; - typedef typename internal::traits::Scalar Scalar; - typedef typename internal::packet_traits::type PacketScalar; - typedef typename NumTraits::Real RealScalar; - - using Base::coeff; - using Base::rows; - using Base::cols; - using Base::size; - using Base::derived; - using Base::rowIndexByOuterInner; - using Base::colIndexByOuterInner; - using Base::operator[]; - using Base::operator(); - using Base::x; - using Base::y; - using Base::z; - using Base::w; - - /** Short version: don't use this function, use - * \link operator()(Index,Index) \endlink instead. - * - * Long version: this function is similar to - * \link operator()(Index,Index) \endlink, but without the assertion. - * Use this for limiting the performance cost of debugging code when doing - * repeated coefficient access. Only use this when it is guaranteed that the - * parameters \a row and \a col are in range. - * - * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this - * function equivalent to \link operator()(Index,Index) \endlink. - * - * \sa operator()(Index,Index), coeff(Index, Index) const, coeffRef(Index) - */ - EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) - { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - return derived().coeffRef(row, col); - } - - EIGEN_STRONG_INLINE Scalar& - coeffRefByOuterInner(Index outer, Index inner) - { - return coeffRef(rowIndexByOuterInner(outer, inner), - colIndexByOuterInner(outer, inner)); - } - - /** \returns a reference to the coefficient at given the given row and column. - * - * \sa operator[](Index) - */ - - EIGEN_STRONG_INLINE Scalar& - operator()(Index row, Index col) - { - eigen_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - return derived().coeffRef(row, col); - } - - - /** Short version: don't use this function, use - * \link operator[](Index) \endlink instead. - * - * Long version: this function is similar to - * \link operator[](Index) \endlink, but without the assertion. - * Use this for limiting the performance cost of debugging code when doing - * repeated coefficient access. Only use this when it is guaranteed that the - * parameters \a row and \a col are in range. - * - * If EIGEN_INTERNAL_DEBUGGING is defined, an assertion will be made, making this - * function equivalent to \link operator[](Index) \endlink. - * - * \sa operator[](Index), coeff(Index) const, coeffRef(Index,Index) - */ - - EIGEN_STRONG_INLINE Scalar& - coeffRef(Index index) - { - eigen_internal_assert(index >= 0 && index < size()); - return derived().coeffRef(index); - } - - /** \returns a reference to the coefficient at given index. - * - * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. - * - * \sa operator[](Index) const, operator()(Index,Index), x(), y(), z(), w() - */ - - EIGEN_STRONG_INLINE Scalar& - operator[](Index index) - { - #ifndef EIGEN2_SUPPORT - EIGEN_STATIC_ASSERT(Derived::IsVectorAtCompileTime, - THE_BRACKET_OPERATOR_IS_ONLY_FOR_VECTORS__USE_THE_PARENTHESIS_OPERATOR_INSTEAD) - #endif - eigen_assert(index >= 0 && index < size()); - return derived().coeffRef(index); - } - - /** \returns a reference to the coefficient at given index. - * - * This is synonymous to operator[](Index). - * - * This method is allowed only for vector expressions, and for matrix expressions having the LinearAccessBit. - * - * \sa operator[](Index) const, operator()(Index,Index), x(), y(), z(), w() - */ - - EIGEN_STRONG_INLINE Scalar& - operator()(Index index) - { - eigen_assert(index >= 0 && index < size()); - return derived().coeffRef(index); - } - - /** equivalent to operator[](0). */ - - EIGEN_STRONG_INLINE Scalar& - x() { return (*this)[0]; } - - /** equivalent to operator[](1). */ - - EIGEN_STRONG_INLINE Scalar& - y() { return (*this)[1]; } - - /** equivalent to operator[](2). */ - - EIGEN_STRONG_INLINE Scalar& - z() { return (*this)[2]; } - - /** equivalent to operator[](3). */ - - EIGEN_STRONG_INLINE Scalar& - w() { return (*this)[3]; } - - /** \internal - * Stores the given packet of coefficients, at the given row and column of this expression. It is your responsibility - * to ensure that a packet really starts there. This method is only available on expressions having the - * PacketAccessBit. - * - * The \a LoadMode parameter may have the value \a #Aligned or \a #Unaligned. Its effect is to select - * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets - * starting at an address which is a multiple of the packet size. - */ - - template - EIGEN_STRONG_INLINE void writePacket - (Index row, Index col, const typename internal::packet_traits::type& val) - { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - derived().template writePacket(row,col,val); - } - - - /** \internal */ - template - EIGEN_STRONG_INLINE void writePacketByOuterInner - (Index outer, Index inner, const typename internal::packet_traits::type& val) - { - writePacket(rowIndexByOuterInner(outer, inner), - colIndexByOuterInner(outer, inner), - val); - } - - /** \internal - * Stores the given packet of coefficients, at the given index in this expression. It is your responsibility - * to ensure that a packet really starts there. This method is only available on expressions having the - * PacketAccessBit and the LinearAccessBit. - * - * The \a LoadMode parameter may have the value \a Aligned or \a Unaligned. Its effect is to select - * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets - * starting at an address which is a multiple of the packet size. - */ - template - EIGEN_STRONG_INLINE void writePacket - (Index index, const typename internal::packet_traits::type& val) - { - eigen_internal_assert(index >= 0 && index < size()); - derived().template writePacket(index,val); - } - -#ifndef EIGEN_PARSED_BY_DOXYGEN - - /** \internal Copies the coefficient at position (row,col) of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_STRONG_INLINE void copyCoeff(Index row, Index col, const DenseBase& other) - { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - derived().coeffRef(row, col) = other.derived().coeff(row, col); - } - - /** \internal Copies the coefficient at the given index of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_STRONG_INLINE void copyCoeff(Index index, const DenseBase& other) - { - eigen_internal_assert(index >= 0 && index < size()); - derived().coeffRef(index) = other.derived().coeff(index); - } - - - template - EIGEN_STRONG_INLINE void copyCoeffByOuterInner(Index outer, Index inner, const DenseBase& other) - { - const Index row = rowIndexByOuterInner(outer,inner); - const Index col = colIndexByOuterInner(outer,inner); - // derived() is important here: copyCoeff() may be reimplemented in Derived! - derived().copyCoeff(row, col, other); - } - - /** \internal Copies the packet at position (row,col) of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_STRONG_INLINE void copyPacket(Index row, Index col, const DenseBase& other) - { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - derived().template writePacket(row, col, - other.derived().template packet(row, col)); - } - - /** \internal Copies the packet at the given index of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_STRONG_INLINE void copyPacket(Index index, const DenseBase& other) - { - eigen_internal_assert(index >= 0 && index < size()); - derived().template writePacket(index, - other.derived().template packet(index)); - } - - /** \internal */ - template - EIGEN_STRONG_INLINE void copyPacketByOuterInner(Index outer, Index inner, const DenseBase& other) - { - const Index row = rowIndexByOuterInner(outer,inner); - const Index col = colIndexByOuterInner(outer,inner); - // derived() is important here: copyCoeff() may be reimplemented in Derived! - derived().template copyPacket< OtherDerived, StoreMode, LoadMode>(row, col, other); - } -#endif - -}; - -/** \brief Base class providing direct read-only coefficient access to matrices and arrays. - * \ingroup Core_Module - * \tparam Derived Type of the derived class - * \tparam #DirectAccessors Constant indicating direct access - * - * This class defines functions to work with strides which can be used to access entries directly. This class - * inherits DenseCoeffsBase which defines functions to access entries read-only using - * \c operator() . - * - * \sa \ref TopicClassHierarchy - */ -template -class DenseCoeffsBase : public DenseCoeffsBase -{ - public: - - typedef DenseCoeffsBase Base; - typedef typename internal::traits::Index Index; - typedef typename internal::traits::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - - using Base::rows; - using Base::cols; - using Base::size; - using Base::derived; - - /** \returns the pointer increment between two consecutive elements within a slice in the inner direction. - * - * \sa outerStride(), rowStride(), colStride() - */ - inline Index innerStride() const - { - return derived().innerStride(); - } - - /** \returns the pointer increment between two consecutive inner slices (for example, between two consecutive columns - * in a column-major matrix). - * - * \sa innerStride(), rowStride(), colStride() - */ - inline Index outerStride() const - { - return derived().outerStride(); - } - - // FIXME shall we remove it ? - inline Index stride() const - { - return Derived::IsVectorAtCompileTime ? innerStride() : outerStride(); - } - - /** \returns the pointer increment between two consecutive rows. - * - * \sa innerStride(), outerStride(), colStride() - */ - inline Index rowStride() const - { - return Derived::IsRowMajor ? outerStride() : innerStride(); - } - - /** \returns the pointer increment between two consecutive columns. - * - * \sa innerStride(), outerStride(), rowStride() - */ - inline Index colStride() const - { - return Derived::IsRowMajor ? innerStride() : outerStride(); - } -}; - -/** \brief Base class providing direct read/write coefficient access to matrices and arrays. - * \ingroup Core_Module - * \tparam Derived Type of the derived class - * \tparam #DirectWriteAccessors Constant indicating direct access - * - * This class defines functions to work with strides which can be used to access entries directly. This class - * inherits DenseCoeffsBase which defines functions to access entries read/write using - * \c operator(). - * - * \sa \ref TopicClassHierarchy - */ -template -class DenseCoeffsBase - : public DenseCoeffsBase -{ - public: - - typedef DenseCoeffsBase Base; - typedef typename internal::traits::Index Index; - typedef typename internal::traits::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - - using Base::rows; - using Base::cols; - using Base::size; - using Base::derived; - - /** \returns the pointer increment between two consecutive elements within a slice in the inner direction. - * - * \sa outerStride(), rowStride(), colStride() - */ - inline Index innerStride() const - { - return derived().innerStride(); - } - - /** \returns the pointer increment between two consecutive inner slices (for example, between two consecutive columns - * in a column-major matrix). - * - * \sa innerStride(), rowStride(), colStride() - */ - inline Index outerStride() const - { - return derived().outerStride(); - } - - // FIXME shall we remove it ? - inline Index stride() const - { - return Derived::IsVectorAtCompileTime ? innerStride() : outerStride(); - } - - /** \returns the pointer increment between two consecutive rows. - * - * \sa innerStride(), outerStride(), colStride() - */ - inline Index rowStride() const - { - return Derived::IsRowMajor ? outerStride() : innerStride(); - } - - /** \returns the pointer increment between two consecutive columns. - * - * \sa innerStride(), outerStride(), rowStride() - */ - inline Index colStride() const - { - return Derived::IsRowMajor ? innerStride() : outerStride(); - } -}; - -namespace internal { - -template -struct first_aligned_impl -{ - static inline typename Derived::Index run(const Derived&) - { return 0; } -}; - -template -struct first_aligned_impl -{ - static inline typename Derived::Index run(const Derived& m) - { - return internal::first_aligned(&m.const_cast_derived().coeffRef(0,0), m.size()); - } -}; - -/** \internal \returns the index of the first element of the array that is well aligned for vectorization. - * - * There is also the variant first_aligned(const Scalar*, Integer) defined in Memory.h. See it for more - * documentation. - */ -template -static inline typename Derived::Index first_aligned(const Derived& m) -{ - return first_aligned_impl - - ::run(m); -} - -template::ret> -struct inner_stride_at_compile_time -{ - enum { ret = traits::InnerStrideAtCompileTime }; -}; - -template -struct inner_stride_at_compile_time -{ - enum { ret = 0 }; -}; - -template::ret> -struct outer_stride_at_compile_time -{ - enum { ret = traits::OuterStrideAtCompileTime }; -}; - -template -struct outer_stride_at_compile_time -{ - enum { ret = 0 }; -}; - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_DENSECOEFFSBASE_H diff --git a/splinter/src/Core/DenseStorage.h b/splinter/src/Core/DenseStorage.h deleted file mode 100644 index 568493cbae..0000000000 --- a/splinter/src/Core/DenseStorage.h +++ /dev/null @@ -1,434 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2006-2009 Benoit Jacob -// Copyright (C) 2010 Hauke Heibel -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_MATRIXSTORAGE_H -#define EIGEN_MATRIXSTORAGE_H - -#ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN EIGEN_DENSE_STORAGE_CTOR_PLUGIN; -#else - #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN -#endif - -namespace Eigen { - -namespace internal { - -struct constructor_without_unaligned_array_assert {}; - -template void check_static_allocation_size() -{ - // if EIGEN_STACK_ALLOCATION_LIMIT is defined to 0, then no limit - #if EIGEN_STACK_ALLOCATION_LIMIT - EIGEN_STATIC_ASSERT(Size * sizeof(T) <= EIGEN_STACK_ALLOCATION_LIMIT, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG); - #endif -} - -/** \internal - * Static array. If the MatrixOrArrayOptions require auto-alignment, the array will be automatically aligned: - * to 16 bytes boundary if the total size is a multiple of 16 bytes. - */ -template -struct plain_array -{ - T array[Size]; - - plain_array() - { - check_static_allocation_size(); - } - - plain_array(constructor_without_unaligned_array_assert) - { - check_static_allocation_size(); - } -}; - -#if defined(EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT) - #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) -#elif EIGEN_GNUC_AT_LEAST(4,7) - // GCC 4.7 is too aggressive in its optimizations and remove the alignement test based on the fact the array is declared to be aligned. - // See this bug report: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53900 - // Hiding the origin of the array pointer behind a function argument seems to do the trick even if the function is inlined: - template - EIGEN_ALWAYS_INLINE PtrType eigen_unaligned_array_assert_workaround_gcc47(PtrType array) { return array; } - #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ - eigen_assert((reinterpret_cast(eigen_unaligned_array_assert_workaround_gcc47(array)) & sizemask) == 0 \ - && "this assertion is explained here: " \ - "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" \ - " **** READ THIS WEB PAGE !!! ****"); -#else - #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ - eigen_assert((reinterpret_cast(array) & sizemask) == 0 \ - && "this assertion is explained here: " \ - "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" \ - " **** READ THIS WEB PAGE !!! ****"); -#endif - -template -struct plain_array -{ - EIGEN_USER_ALIGN16 T array[Size]; - - plain_array() - { - EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(0xf); - check_static_allocation_size(); - } - - plain_array(constructor_without_unaligned_array_assert) - { - check_static_allocation_size(); - } -}; - -template -struct plain_array -{ - EIGEN_USER_ALIGN16 T array[1]; - plain_array() {} - plain_array(constructor_without_unaligned_array_assert) {} -}; - -} // end namespace internal - -/** \internal - * - * \class DenseStorage - * \ingroup Core_Module - * - * \brief Stores the data of a matrix - * - * This class stores the data of fixed-size, dynamic-size or mixed matrices - * in a way as compact as possible. - * - * \sa Matrix - */ -template class DenseStorage; - -// purely fixed-size matrix -template class DenseStorage -{ - internal::plain_array m_data; - public: - DenseStorage() {} - DenseStorage(internal::constructor_without_unaligned_array_assert) - : m_data(internal::constructor_without_unaligned_array_assert()) {} - DenseStorage(const DenseStorage& other) : m_data(other.m_data) {} - DenseStorage& operator=(const DenseStorage& other) - { - if (this != &other) m_data = other.m_data; - return *this; - } - DenseStorage(DenseIndex,DenseIndex,DenseIndex) {} - void swap(DenseStorage& other) { std::swap(m_data,other.m_data); } - static DenseIndex rows(void) {return _Rows;} - static DenseIndex cols(void) {return _Cols;} - void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {} - void resize(DenseIndex,DenseIndex,DenseIndex) {} - const T *data() const { return m_data.array; } - T *data() { return m_data.array; } -}; - -// null matrix -template class DenseStorage -{ - public: - DenseStorage() {} - DenseStorage(internal::constructor_without_unaligned_array_assert) {} - DenseStorage(const DenseStorage&) {} - DenseStorage& operator=(const DenseStorage&) { return *this; } - DenseStorage(DenseIndex,DenseIndex,DenseIndex) {} - void swap(DenseStorage& ) {} - static DenseIndex rows(void) {return _Rows;} - static DenseIndex cols(void) {return _Cols;} - void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {} - void resize(DenseIndex,DenseIndex,DenseIndex) {} - const T *data() const { return 0; } - T *data() { return 0; } -}; - -// more specializations for null matrices; these are necessary to resolve ambiguities -template class DenseStorage -: public DenseStorage { }; - -template class DenseStorage -: public DenseStorage { }; - -template class DenseStorage -: public DenseStorage { }; - -// dynamic-size matrix with fixed-size storage -template class DenseStorage -{ - internal::plain_array m_data; - DenseIndex m_rows; - DenseIndex m_cols; - public: - DenseStorage() : m_rows(0), m_cols(0) {} - DenseStorage(internal::constructor_without_unaligned_array_assert) - : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0), m_cols(0) {} - DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows), m_cols(other.m_cols) {} - DenseStorage& operator=(const DenseStorage& other) - { - if (this != &other) - { - m_data = other.m_data; - m_rows = other.m_rows; - m_cols = other.m_cols; - } - return *this; - } - DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) : m_rows(nbRows), m_cols(nbCols) {} - void swap(DenseStorage& other) - { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } - DenseIndex rows() const {return m_rows;} - DenseIndex cols() const {return m_cols;} - void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; } - void resize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; } - const T *data() const { return m_data.array; } - T *data() { return m_data.array; } -}; - -// dynamic-size matrix with fixed-size storage and fixed width -template class DenseStorage -{ - internal::plain_array m_data; - DenseIndex m_rows; - public: - DenseStorage() : m_rows(0) {} - DenseStorage(internal::constructor_without_unaligned_array_assert) - : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0) {} - DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows) {} - DenseStorage& operator=(const DenseStorage& other) - { - if (this != &other) - { - m_data = other.m_data; - m_rows = other.m_rows; - } - return *this; - } - DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex) : m_rows(nbRows) {} - void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } - DenseIndex rows(void) const {return m_rows;} - DenseIndex cols(void) const {return _Cols;} - void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; } - void resize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; } - const T *data() const { return m_data.array; } - T *data() { return m_data.array; } -}; - -// dynamic-size matrix with fixed-size storage and fixed height -template class DenseStorage -{ - internal::plain_array m_data; - DenseIndex m_cols; - public: - DenseStorage() : m_cols(0) {} - DenseStorage(internal::constructor_without_unaligned_array_assert) - : m_data(internal::constructor_without_unaligned_array_assert()), m_cols(0) {} - DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_cols(other.m_cols) {} - DenseStorage& operator=(const DenseStorage& other) - { - if (this != &other) - { - m_data = other.m_data; - m_cols = other.m_cols; - } - return *this; - } - DenseStorage(DenseIndex, DenseIndex, DenseIndex nbCols) : m_cols(nbCols) {} - void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } - DenseIndex rows(void) const {return _Rows;} - DenseIndex cols(void) const {return m_cols;} - void conservativeResize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; } - void resize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; } - const T *data() const { return m_data.array; } - T *data() { return m_data.array; } -}; - -// purely dynamic matrix. -template class DenseStorage -{ - T *m_data; - DenseIndex m_rows; - DenseIndex m_cols; - public: - DenseStorage() : m_data(0), m_rows(0), m_cols(0) {} - DenseStorage(internal::constructor_without_unaligned_array_assert) - : m_data(0), m_rows(0), m_cols(0) {} - DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) - : m_data(internal::conditional_aligned_new_auto(size)), m_rows(nbRows), m_cols(nbCols) - { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } -#ifdef EIGEN_HAVE_RVALUE_REFERENCES - DenseStorage(DenseStorage&& other) - : m_data(std::move(other.m_data)) - , m_rows(std::move(other.m_rows)) - , m_cols(std::move(other.m_cols)) - { - other.m_data = nullptr; - } - DenseStorage& operator=(DenseStorage&& other) - { - using std::swap; - swap(m_data, other.m_data); - swap(m_rows, other.m_rows); - swap(m_cols, other.m_cols); - return *this; - } -#endif - ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, m_rows*m_cols); } - void swap(DenseStorage& other) - { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } - DenseIndex rows(void) const {return m_rows;} - DenseIndex cols(void) const {return m_cols;} - void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) - { - m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, m_rows*m_cols); - m_rows = nbRows; - m_cols = nbCols; - } - void resize(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) - { - if(size != m_rows*m_cols) - { - internal::conditional_aligned_delete_auto(m_data, m_rows*m_cols); - if (size) - m_data = internal::conditional_aligned_new_auto(size); - else - m_data = 0; - EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN - } - m_rows = nbRows; - m_cols = nbCols; - } - const T *data() const { return m_data; } - T *data() { return m_data; } - private: - DenseStorage(const DenseStorage&); - DenseStorage& operator=(const DenseStorage&); -}; - -// matrix with dynamic width and fixed height (so that matrix has dynamic size). -template class DenseStorage -{ - T *m_data; - DenseIndex m_cols; - public: - DenseStorage() : m_data(0), m_cols(0) {} - DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_cols(0) {} - DenseStorage(DenseIndex size, DenseIndex, DenseIndex nbCols) : m_data(internal::conditional_aligned_new_auto(size)), m_cols(nbCols) - { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } -#ifdef EIGEN_HAVE_RVALUE_REFERENCES - DenseStorage(DenseStorage&& other) - : m_data(std::move(other.m_data)) - , m_cols(std::move(other.m_cols)) - { - other.m_data = nullptr; - } - DenseStorage& operator=(DenseStorage&& other) - { - using std::swap; - swap(m_data, other.m_data); - swap(m_cols, other.m_cols); - return *this; - } -#endif - ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Rows*m_cols); } - void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } - static DenseIndex rows(void) {return _Rows;} - DenseIndex cols(void) const {return m_cols;} - void conservativeResize(DenseIndex size, DenseIndex, DenseIndex nbCols) - { - m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, _Rows*m_cols); - m_cols = nbCols; - } - EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex, DenseIndex nbCols) - { - if(size != _Rows*m_cols) - { - internal::conditional_aligned_delete_auto(m_data, _Rows*m_cols); - if (size) - m_data = internal::conditional_aligned_new_auto(size); - else - m_data = 0; - EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN - } - m_cols = nbCols; - } - const T *data() const { return m_data; } - T *data() { return m_data; } - private: - DenseStorage(const DenseStorage&); - DenseStorage& operator=(const DenseStorage&); -}; - -// matrix with dynamic height and fixed width (so that matrix has dynamic size). -template class DenseStorage -{ - T *m_data; - DenseIndex m_rows; - public: - DenseStorage() : m_data(0), m_rows(0) {} - DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0) {} - DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex) : m_data(internal::conditional_aligned_new_auto(size)), m_rows(nbRows) - { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } -#ifdef EIGEN_HAVE_RVALUE_REFERENCES - DenseStorage(DenseStorage&& other) - : m_data(std::move(other.m_data)) - , m_rows(std::move(other.m_rows)) - { - other.m_data = nullptr; - } - DenseStorage& operator=(DenseStorage&& other) - { - using std::swap; - swap(m_data, other.m_data); - swap(m_rows, other.m_rows); - return *this; - } -#endif - ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Cols*m_rows); } - void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } - DenseIndex rows(void) const {return m_rows;} - static DenseIndex cols(void) {return _Cols;} - void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex) - { - m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, m_rows*_Cols); - m_rows = nbRows; - } - EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex nbRows, DenseIndex) - { - if(size != m_rows*_Cols) - { - internal::conditional_aligned_delete_auto(m_data, _Cols*m_rows); - if (size) - m_data = internal::conditional_aligned_new_auto(size); - else - m_data = 0; - EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN - } - m_rows = nbRows; - } - const T *data() const { return m_data; } - T *data() { return m_data; } - private: - DenseStorage(const DenseStorage&); - DenseStorage& operator=(const DenseStorage&); -}; - -} // end namespace Eigen - -#endif // EIGEN_MATRIX_H diff --git a/splinter/src/Core/Diagonal.h b/splinter/src/Core/Diagonal.h deleted file mode 100644 index 68cf6d4b04..0000000000 --- a/splinter/src/Core/Diagonal.h +++ /dev/null @@ -1,237 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2007-2009 Benoit Jacob -// Copyright (C) 2009-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_DIAGONAL_H -#define EIGEN_DIAGONAL_H - -namespace Eigen { - -/** \class Diagonal - * \ingroup Core_Module - * - * \brief Expression of a diagonal/subdiagonal/superdiagonal in a matrix - * - * \param MatrixType the type of the object in which we are taking a sub/main/super diagonal - * \param DiagIndex the index of the sub/super diagonal. The default is 0 and it means the main diagonal. - * A positive value means a superdiagonal, a negative value means a subdiagonal. - * You can also use Dynamic so the index can be set at runtime. - * - * The matrix is not required to be square. - * - * This class represents an expression of the main diagonal, or any sub/super diagonal - * of a square matrix. It is the return type of MatrixBase::diagonal() and MatrixBase::diagonal(Index) and most of the - * time this is the only way it is used. - * - * \sa MatrixBase::diagonal(), MatrixBase::diagonal(Index) - */ - -namespace internal { -template -struct traits > - : traits -{ - typedef typename nested::type MatrixTypeNested; - typedef typename remove_reference::type _MatrixTypeNested; - typedef typename MatrixType::StorageKind StorageKind; - enum { - RowsAtCompileTime = (int(DiagIndex) == DynamicIndex || int(MatrixType::SizeAtCompileTime) == Dynamic) ? Dynamic - : (EIGEN_PLAIN_ENUM_MIN(MatrixType::RowsAtCompileTime - EIGEN_PLAIN_ENUM_MAX(-DiagIndex, 0), - MatrixType::ColsAtCompileTime - EIGEN_PLAIN_ENUM_MAX( DiagIndex, 0))), - ColsAtCompileTime = 1, - MaxRowsAtCompileTime = int(MatrixType::MaxSizeAtCompileTime) == Dynamic ? Dynamic - : DiagIndex == DynamicIndex ? EIGEN_SIZE_MIN_PREFER_FIXED(MatrixType::MaxRowsAtCompileTime, - MatrixType::MaxColsAtCompileTime) - : (EIGEN_PLAIN_ENUM_MIN(MatrixType::MaxRowsAtCompileTime - EIGEN_PLAIN_ENUM_MAX(-DiagIndex, 0), - MatrixType::MaxColsAtCompileTime - EIGEN_PLAIN_ENUM_MAX( DiagIndex, 0))), - MaxColsAtCompileTime = 1, - MaskLvalueBit = is_lvalue::value ? LvalueBit : 0, - Flags = (unsigned int)_MatrixTypeNested::Flags & (HereditaryBits | LinearAccessBit | MaskLvalueBit | DirectAccessBit) & ~RowMajorBit, - CoeffReadCost = _MatrixTypeNested::CoeffReadCost, - MatrixTypeOuterStride = outer_stride_at_compile_time::ret, - InnerStrideAtCompileTime = MatrixTypeOuterStride == Dynamic ? Dynamic : MatrixTypeOuterStride+1, - OuterStrideAtCompileTime = 0 - }; -}; -} - -template class Diagonal - : public internal::dense_xpr_base< Diagonal >::type -{ - public: - - enum { DiagIndex = _DiagIndex }; - typedef typename internal::dense_xpr_base::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(Diagonal) - - inline Diagonal(MatrixType& matrix, Index a_index = DiagIndex) : m_matrix(matrix), m_index(a_index) {} - - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Diagonal) - - inline Index rows() const - { return m_index.value()<0 ? (std::min)(m_matrix.cols(),m_matrix.rows()+m_index.value()) : (std::min)(m_matrix.rows(),m_matrix.cols()-m_index.value()); } - - inline Index cols() const { return 1; } - - inline Index innerStride() const - { - return m_matrix.outerStride() + 1; - } - - inline Index outerStride() const - { - return 0; - } - - typedef typename internal::conditional< - internal::is_lvalue::value, - Scalar, - const Scalar - >::type ScalarWithConstIfNotLvalue; - - inline ScalarWithConstIfNotLvalue* data() { return &(m_matrix.const_cast_derived().coeffRef(rowOffset(), colOffset())); } - inline const Scalar* data() const { return &(m_matrix.const_cast_derived().coeffRef(rowOffset(), colOffset())); } - - inline Scalar& coeffRef(Index row, Index) - { - EIGEN_STATIC_ASSERT_LVALUE(MatrixType) - return m_matrix.const_cast_derived().coeffRef(row+rowOffset(), row+colOffset()); - } - - inline const Scalar& coeffRef(Index row, Index) const - { - return m_matrix.const_cast_derived().coeffRef(row+rowOffset(), row+colOffset()); - } - - inline CoeffReturnType coeff(Index row, Index) const - { - return m_matrix.coeff(row+rowOffset(), row+colOffset()); - } - - inline Scalar& coeffRef(Index idx) - { - EIGEN_STATIC_ASSERT_LVALUE(MatrixType) - return m_matrix.const_cast_derived().coeffRef(idx+rowOffset(), idx+colOffset()); - } - - inline const Scalar& coeffRef(Index idx) const - { - return m_matrix.const_cast_derived().coeffRef(idx+rowOffset(), idx+colOffset()); - } - - inline CoeffReturnType coeff(Index idx) const - { - return m_matrix.coeff(idx+rowOffset(), idx+colOffset()); - } - - const typename internal::remove_all::type& - nestedExpression() const - { - return m_matrix; - } - - int index() const - { - return m_index.value(); - } - - protected: - typename MatrixType::Nested m_matrix; - const internal::variable_if_dynamicindex m_index; - - private: - // some compilers may fail to optimize std::max etc in case of compile-time constants... - EIGEN_STRONG_INLINE Index absDiagIndex() const { return m_index.value()>0 ? m_index.value() : -m_index.value(); } - EIGEN_STRONG_INLINE Index rowOffset() const { return m_index.value()>0 ? 0 : -m_index.value(); } - EIGEN_STRONG_INLINE Index colOffset() const { return m_index.value()>0 ? m_index.value() : 0; } - // triger a compile time error is someone try to call packet - template typename MatrixType::PacketReturnType packet(Index) const; - template typename MatrixType::PacketReturnType packet(Index,Index) const; -}; - -/** \returns an expression of the main diagonal of the matrix \c *this - * - * \c *this is not required to be square. - * - * Example: \include MatrixBase_diagonal.cpp - * Output: \verbinclude MatrixBase_diagonal.out - * - * \sa class Diagonal */ -template -inline typename MatrixBase::DiagonalReturnType -MatrixBase::diagonal() -{ - return derived(); -} - -/** This is the const version of diagonal(). */ -template -inline typename MatrixBase::ConstDiagonalReturnType -MatrixBase::diagonal() const -{ - return ConstDiagonalReturnType(derived()); -} - -/** \returns an expression of the \a DiagIndex-th sub or super diagonal of the matrix \c *this - * - * \c *this is not required to be square. - * - * The template parameter \a DiagIndex represent a super diagonal if \a DiagIndex > 0 - * and a sub diagonal otherwise. \a DiagIndex == 0 is equivalent to the main diagonal. - * - * Example: \include MatrixBase_diagonal_int.cpp - * Output: \verbinclude MatrixBase_diagonal_int.out - * - * \sa MatrixBase::diagonal(), class Diagonal */ -template -inline typename MatrixBase::DiagonalDynamicIndexReturnType -MatrixBase::diagonal(Index index) -{ - return DiagonalDynamicIndexReturnType(derived(), index); -} - -/** This is the const version of diagonal(Index). */ -template -inline typename MatrixBase::ConstDiagonalDynamicIndexReturnType -MatrixBase::diagonal(Index index) const -{ - return ConstDiagonalDynamicIndexReturnType(derived(), index); -} - -/** \returns an expression of the \a DiagIndex-th sub or super diagonal of the matrix \c *this - * - * \c *this is not required to be square. - * - * The template parameter \a DiagIndex represent a super diagonal if \a DiagIndex > 0 - * and a sub diagonal otherwise. \a DiagIndex == 0 is equivalent to the main diagonal. - * - * Example: \include MatrixBase_diagonal_template_int.cpp - * Output: \verbinclude MatrixBase_diagonal_template_int.out - * - * \sa MatrixBase::diagonal(), class Diagonal */ -template -template -inline typename MatrixBase::template DiagonalIndexReturnType::Type -MatrixBase::diagonal() -{ - return derived(); -} - -/** This is the const version of diagonal(). */ -template -template -inline typename MatrixBase::template ConstDiagonalIndexReturnType::Type -MatrixBase::diagonal() const -{ - return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_DIAGONAL_H diff --git a/splinter/src/Core/DiagonalMatrix.h b/splinter/src/Core/DiagonalMatrix.h deleted file mode 100644 index e6c220f419..0000000000 --- a/splinter/src/Core/DiagonalMatrix.h +++ /dev/null @@ -1,313 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Gael Guennebaud -// Copyright (C) 2007-2009 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_DIAGONALMATRIX_H -#define EIGEN_DIAGONALMATRIX_H - -namespace Eigen { - -#ifndef EIGEN_PARSED_BY_DOXYGEN -template -class DiagonalBase : public EigenBase -{ - public: - typedef typename internal::traits::DiagonalVectorType DiagonalVectorType; - typedef typename DiagonalVectorType::Scalar Scalar; - typedef typename DiagonalVectorType::RealScalar RealScalar; - typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; - - enum { - RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - MaxRowsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, - MaxColsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, - IsVectorAtCompileTime = 0, - Flags = 0 - }; - - typedef Matrix DenseMatrixType; - typedef DenseMatrixType DenseType; - typedef DiagonalMatrix PlainObject; - - inline const Derived& derived() const { return *static_cast(this); } - inline Derived& derived() { return *static_cast(this); } - - DenseMatrixType toDenseMatrix() const { return derived(); } - template - void evalTo(MatrixBase &other) const; - template - void addTo(MatrixBase &other) const - { other.diagonal() += diagonal(); } - template - void subTo(MatrixBase &other) const - { other.diagonal() -= diagonal(); } - - inline const DiagonalVectorType& diagonal() const { return derived().diagonal(); } - inline DiagonalVectorType& diagonal() { return derived().diagonal(); } - - inline Index rows() const { return diagonal().size(); } - inline Index cols() const { return diagonal().size(); } - - /** \returns the diagonal matrix product of \c *this by the matrix \a matrix. - */ - template - const DiagonalProduct - operator*(const MatrixBase &matrix) const - { - return DiagonalProduct(matrix.derived(), derived()); - } - - inline const DiagonalWrapper, const DiagonalVectorType> > - inverse() const - { - return diagonal().cwiseInverse(); - } - - inline const DiagonalWrapper, const DiagonalVectorType> > - operator*(const Scalar& scalar) const - { - return diagonal() * scalar; - } - friend inline const DiagonalWrapper, const DiagonalVectorType> > - operator*(const Scalar& scalar, const DiagonalBase& other) - { - return other.diagonal() * scalar; - } - - #ifdef EIGEN2_SUPPORT - template - bool isApprox(const DiagonalBase& other, typename NumTraits::Real precision = NumTraits::dummy_precision()) const - { - return diagonal().isApprox(other.diagonal(), precision); - } - template - bool isApprox(const MatrixBase& other, typename NumTraits::Real precision = NumTraits::dummy_precision()) const - { - return toDenseMatrix().isApprox(other, precision); - } - #endif -}; - -template -template -void DiagonalBase::evalTo(MatrixBase &other) const -{ - other.setZero(); - other.diagonal() = diagonal(); -} -#endif - -/** \class DiagonalMatrix - * \ingroup Core_Module - * - * \brief Represents a diagonal matrix with its storage - * - * \param _Scalar the type of coefficients - * \param SizeAtCompileTime the dimension of the matrix, or Dynamic - * \param MaxSizeAtCompileTime the dimension of the matrix, or Dynamic. This parameter is optional and defaults - * to SizeAtCompileTime. Most of the time, you do not need to specify it. - * - * \sa class DiagonalWrapper - */ - -namespace internal { -template -struct traits > - : traits > -{ - typedef Matrix<_Scalar,SizeAtCompileTime,1,0,MaxSizeAtCompileTime,1> DiagonalVectorType; - typedef Dense StorageKind; - typedef DenseIndex Index; - enum { - Flags = LvalueBit - }; -}; -} -template -class DiagonalMatrix - : public DiagonalBase > -{ - public: - #ifndef EIGEN_PARSED_BY_DOXYGEN - typedef typename internal::traits::DiagonalVectorType DiagonalVectorType; - typedef const DiagonalMatrix& Nested; - typedef _Scalar Scalar; - typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; - #endif - - protected: - - DiagonalVectorType m_diagonal; - - public: - - /** const version of diagonal(). */ - inline const DiagonalVectorType& diagonal() const { return m_diagonal; } - /** \returns a reference to the stored vector of diagonal coefficients. */ - inline DiagonalVectorType& diagonal() { return m_diagonal; } - - /** Default constructor without initialization */ - inline DiagonalMatrix() {} - - /** Constructs a diagonal matrix with given dimension */ - inline DiagonalMatrix(Index dim) : m_diagonal(dim) {} - - /** 2D constructor. */ - inline DiagonalMatrix(const Scalar& x, const Scalar& y) : m_diagonal(x,y) {} - - /** 3D constructor. */ - inline DiagonalMatrix(const Scalar& x, const Scalar& y, const Scalar& z) : m_diagonal(x,y,z) {} - - /** Copy constructor. */ - template - inline DiagonalMatrix(const DiagonalBase& other) : m_diagonal(other.diagonal()) {} - - #ifndef EIGEN_PARSED_BY_DOXYGEN - /** copy constructor. prevent a default copy constructor from hiding the other templated constructor */ - inline DiagonalMatrix(const DiagonalMatrix& other) : m_diagonal(other.diagonal()) {} - #endif - - /** generic constructor from expression of the diagonal coefficients */ - template - explicit inline DiagonalMatrix(const MatrixBase& other) : m_diagonal(other) - {} - - /** Copy operator. */ - template - DiagonalMatrix& operator=(const DiagonalBase& other) - { - m_diagonal = other.diagonal(); - return *this; - } - - #ifndef EIGEN_PARSED_BY_DOXYGEN - /** This is a special case of the templated operator=. Its purpose is to - * prevent a default operator= from hiding the templated operator=. - */ - DiagonalMatrix& operator=(const DiagonalMatrix& other) - { - m_diagonal = other.diagonal(); - return *this; - } - #endif - - /** Resizes to given size. */ - inline void resize(Index size) { m_diagonal.resize(size); } - /** Sets all coefficients to zero. */ - inline void setZero() { m_diagonal.setZero(); } - /** Resizes and sets all coefficients to zero. */ - inline void setZero(Index size) { m_diagonal.setZero(size); } - /** Sets this matrix to be the identity matrix of the current size. */ - inline void setIdentity() { m_diagonal.setOnes(); } - /** Sets this matrix to be the identity matrix of the given size. */ - inline void setIdentity(Index size) { m_diagonal.setOnes(size); } -}; - -/** \class DiagonalWrapper - * \ingroup Core_Module - * - * \brief Expression of a diagonal matrix - * - * \param _DiagonalVectorType the type of the vector of diagonal coefficients - * - * This class is an expression of a diagonal matrix, but not storing its own vector of diagonal coefficients, - * instead wrapping an existing vector expression. It is the return type of MatrixBase::asDiagonal() - * and most of the time this is the only way that it is used. - * - * \sa class DiagonalMatrix, class DiagonalBase, MatrixBase::asDiagonal() - */ - -namespace internal { -template -struct traits > -{ - typedef _DiagonalVectorType DiagonalVectorType; - typedef typename DiagonalVectorType::Scalar Scalar; - typedef typename DiagonalVectorType::Index Index; - typedef typename DiagonalVectorType::StorageKind StorageKind; - enum { - RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - MaxRowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - MaxColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - Flags = traits::Flags & LvalueBit - }; -}; -} - -template -class DiagonalWrapper - : public DiagonalBase >, internal::no_assignment_operator -{ - public: - #ifndef EIGEN_PARSED_BY_DOXYGEN - typedef _DiagonalVectorType DiagonalVectorType; - typedef DiagonalWrapper Nested; - #endif - - /** Constructor from expression of diagonal coefficients to wrap. */ - inline DiagonalWrapper(DiagonalVectorType& a_diagonal) : m_diagonal(a_diagonal) {} - - /** \returns a const reference to the wrapped expression of diagonal coefficients. */ - const DiagonalVectorType& diagonal() const { return m_diagonal; } - - protected: - typename DiagonalVectorType::Nested m_diagonal; -}; - -/** \returns a pseudo-expression of a diagonal matrix with *this as vector of diagonal coefficients - * - * \only_for_vectors - * - * Example: \include MatrixBase_asDiagonal.cpp - * Output: \verbinclude MatrixBase_asDiagonal.out - * - * \sa class DiagonalWrapper, class DiagonalMatrix, diagonal(), isDiagonal() - **/ -template -inline const DiagonalWrapper -MatrixBase::asDiagonal() const -{ - return derived(); -} - -/** \returns true if *this is approximately equal to a diagonal matrix, - * within the precision given by \a prec. - * - * Example: \include MatrixBase_isDiagonal.cpp - * Output: \verbinclude MatrixBase_isDiagonal.out - * - * \sa asDiagonal() - */ -template -bool MatrixBase::isDiagonal(const RealScalar& prec) const -{ - using std::abs; - if(cols() != rows()) return false; - RealScalar maxAbsOnDiagonal = static_cast(-1); - for(Index j = 0; j < cols(); ++j) - { - RealScalar absOnDiagonal = abs(coeff(j,j)); - if(absOnDiagonal > maxAbsOnDiagonal) maxAbsOnDiagonal = absOnDiagonal; - } - for(Index j = 0; j < cols(); ++j) - for(Index i = 0; i < j; ++i) - { - if(!internal::isMuchSmallerThan(coeff(i, j), maxAbsOnDiagonal, prec)) return false; - if(!internal::isMuchSmallerThan(coeff(j, i), maxAbsOnDiagonal, prec)) return false; - } - return true; -} - -} // end namespace Eigen - -#endif // EIGEN_DIAGONALMATRIX_H diff --git a/splinter/src/Core/DiagonalProduct.h b/splinter/src/Core/DiagonalProduct.h deleted file mode 100644 index cc6b536e19..0000000000 --- a/splinter/src/Core/DiagonalProduct.h +++ /dev/null @@ -1,131 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2007-2009 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_DIAGONALPRODUCT_H -#define EIGEN_DIAGONALPRODUCT_H - -namespace Eigen { - -namespace internal { -template -struct traits > - : traits -{ - typedef typename scalar_product_traits::ReturnType Scalar; - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime, - MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, - - _StorageOrder = MatrixType::Flags & RowMajorBit ? RowMajor : ColMajor, - _ScalarAccessOnDiag = !((int(_StorageOrder) == ColMajor && int(ProductOrder) == OnTheLeft) - ||(int(_StorageOrder) == RowMajor && int(ProductOrder) == OnTheRight)), - _SameTypes = is_same::value, - // FIXME currently we need same types, but in the future the next rule should be the one - //_Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && ((!_PacketOnDiag) || (_SameTypes && bool(int(DiagonalType::DiagonalVectorType::Flags)&PacketAccessBit))), - _Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && _SameTypes && (_ScalarAccessOnDiag || (bool(int(DiagonalType::DiagonalVectorType::Flags)&PacketAccessBit))), - _LinearAccessMask = (RowsAtCompileTime==1 || ColsAtCompileTime==1) ? LinearAccessBit : 0, - - Flags = ((HereditaryBits|_LinearAccessMask|AlignedBit) & (unsigned int)(MatrixType::Flags)) | (_Vectorizable ? PacketAccessBit : 0),//(int(MatrixType::Flags)&int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit), - Cost0 = EIGEN_ADD_COST(NumTraits::MulCost, MatrixType::CoeffReadCost), - CoeffReadCost = EIGEN_ADD_COST(Cost0,DiagonalType::DiagonalVectorType::CoeffReadCost) - }; -}; -} - -template -class DiagonalProduct : internal::no_assignment_operator, - public MatrixBase > -{ - public: - - typedef MatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(DiagonalProduct) - - inline DiagonalProduct(const MatrixType& matrix, const DiagonalType& diagonal) - : m_matrix(matrix), m_diagonal(diagonal) - { - eigen_assert(diagonal.diagonal().size() == (ProductOrder == OnTheLeft ? matrix.rows() : matrix.cols())); - } - - EIGEN_STRONG_INLINE Index rows() const { return m_matrix.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return m_matrix.cols(); } - - EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const - { - return m_diagonal.diagonal().coeff(ProductOrder == OnTheLeft ? row : col) * m_matrix.coeff(row, col); - } - - EIGEN_STRONG_INLINE const Scalar coeff(Index idx) const - { - enum { - StorageOrder = int(MatrixType::Flags) & RowMajorBit ? RowMajor : ColMajor - }; - return coeff(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const - { - enum { - StorageOrder = Flags & RowMajorBit ? RowMajor : ColMajor - }; - const Index indexInDiagonalVector = ProductOrder == OnTheLeft ? row : col; - return packet_impl(row,col,indexInDiagonalVector,typename internal::conditional< - ((int(StorageOrder) == RowMajor && int(ProductOrder) == OnTheLeft) - ||(int(StorageOrder) == ColMajor && int(ProductOrder) == OnTheRight)), internal::true_type, internal::false_type>::type()); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index idx) const - { - enum { - StorageOrder = int(MatrixType::Flags) & RowMajorBit ? RowMajor : ColMajor - }; - return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); - } - - protected: - template - EIGEN_STRONG_INLINE PacketScalar packet_impl(Index row, Index col, Index id, internal::true_type) const - { - return internal::pmul(m_matrix.template packet(row, col), - internal::pset1(m_diagonal.diagonal().coeff(id))); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet_impl(Index row, Index col, Index id, internal::false_type) const - { - enum { - InnerSize = (MatrixType::Flags & RowMajorBit) ? MatrixType::ColsAtCompileTime : MatrixType::RowsAtCompileTime, - DiagonalVectorPacketLoadMode = (LoadMode == Aligned && (((InnerSize%16) == 0) || (int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit)==AlignedBit) ? Aligned : Unaligned) - }; - return internal::pmul(m_matrix.template packet(row, col), - m_diagonal.diagonal().template packet(id)); - } - - typename MatrixType::Nested m_matrix; - typename DiagonalType::Nested m_diagonal; -}; - -/** \returns the diagonal matrix product of \c *this by the diagonal matrix \a diagonal. - */ -template -template -inline const DiagonalProduct -MatrixBase::operator*(const DiagonalBase &a_diagonal) const -{ - return DiagonalProduct(derived(), a_diagonal.derived()); -} - -} // end namespace Eigen - -#endif // EIGEN_DIAGONALPRODUCT_H diff --git a/splinter/src/Core/Dot.h b/splinter/src/Core/Dot.h deleted file mode 100644 index 9d7651f1fd..0000000000 --- a/splinter/src/Core/Dot.h +++ /dev/null @@ -1,263 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2008, 2010 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_DOT_H -#define EIGEN_DOT_H - -namespace Eigen { - -namespace internal { - -// helper function for dot(). The problem is that if we put that in the body of dot(), then upon calling dot -// with mismatched types, the compiler emits errors about failing to instantiate cwiseProduct BEFORE -// looking at the static assertions. Thus this is a trick to get better compile errors. -template -struct dot_nocheck -{ - typedef typename scalar_product_traits::Scalar,typename traits::Scalar>::ReturnType ResScalar; - static inline ResScalar run(const MatrixBase& a, const MatrixBase& b) - { - return a.template binaryExpr::Scalar,typename traits::Scalar> >(b).sum(); - } -}; - -template -struct dot_nocheck -{ - typedef typename scalar_product_traits::Scalar,typename traits::Scalar>::ReturnType ResScalar; - static inline ResScalar run(const MatrixBase& a, const MatrixBase& b) - { - return a.transpose().template binaryExpr::Scalar,typename traits::Scalar> >(b).sum(); - } -}; - -} // end namespace internal - -/** \returns the dot product of *this with other. - * - * \only_for_vectors - * - * \note If the scalar type is complex numbers, then this function returns the hermitian - * (sesquilinear) dot product, conjugate-linear in the first variable and linear in the - * second variable. - * - * \sa squaredNorm(), norm() - */ -template -template -typename internal::scalar_product_traits::Scalar,typename internal::traits::Scalar>::ReturnType -MatrixBase::dot(const MatrixBase& other) const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) - EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived) - typedef internal::scalar_conj_product_op func; - EIGEN_CHECK_BINARY_COMPATIBILIY(func,Scalar,typename OtherDerived::Scalar); - - eigen_assert(size() == other.size()); - - return internal::dot_nocheck::run(*this, other); -} - -#ifdef EIGEN2_SUPPORT -/** \returns the dot product of *this with other, with the Eigen2 convention that the dot product is linear in the first variable - * (conjugating the second variable). Of course this only makes a difference in the complex case. - * - * This method is only available in EIGEN2_SUPPORT mode. - * - * \only_for_vectors - * - * \sa dot() - */ -template -template -typename internal::traits::Scalar -MatrixBase::eigen2_dot(const MatrixBase& other) const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) - EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived) - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - - eigen_assert(size() == other.size()); - - return internal::dot_nocheck::run(other,*this); -} -#endif - - -//---------- implementation of L2 norm and related functions ---------- - -/** \returns, for vectors, the squared \em l2 norm of \c *this, and for matrices the Frobenius norm. - * In both cases, it consists in the sum of the square of all the matrix entries. - * For vectors, this is also equals to the dot product of \c *this with itself. - * - * \sa dot(), norm() - */ -template -EIGEN_STRONG_INLINE typename NumTraits::Scalar>::Real MatrixBase::squaredNorm() const -{ - return numext::real((*this).cwiseAbs2().sum()); -} - -/** \returns, for vectors, the \em l2 norm of \c *this, and for matrices the Frobenius norm. - * In both cases, it consists in the square root of the sum of the square of all the matrix entries. - * For vectors, this is also equals to the square root of the dot product of \c *this with itself. - * - * \sa dot(), squaredNorm() - */ -template -inline typename NumTraits::Scalar>::Real MatrixBase::norm() const -{ - using std::sqrt; - return sqrt(squaredNorm()); -} - -/** \returns an expression of the quotient of *this by its own norm. - * - * \only_for_vectors - * - * \sa norm(), normalize() - */ -template -inline const typename MatrixBase::PlainObject -MatrixBase::normalized() const -{ - typedef typename internal::nested::type Nested; - typedef typename internal::remove_reference::type _Nested; - _Nested n(derived()); - return n / n.norm(); -} - -/** Normalizes the vector, i.e. divides it by its own norm. - * - * \only_for_vectors - * - * \sa norm(), normalized() - */ -template -inline void MatrixBase::normalize() -{ - *this /= norm(); -} - -//---------- implementation of other norms ---------- - -namespace internal { - -template -struct lpNorm_selector -{ - typedef typename NumTraits::Scalar>::Real RealScalar; - static inline RealScalar run(const MatrixBase& m) - { - using std::pow; - return pow(m.cwiseAbs().array().pow(p).sum(), RealScalar(1)/p); - } -}; - -template -struct lpNorm_selector -{ - static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) - { - return m.cwiseAbs().sum(); - } -}; - -template -struct lpNorm_selector -{ - static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) - { - return m.norm(); - } -}; - -template -struct lpNorm_selector -{ - static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) - { - return m.cwiseAbs().maxCoeff(); - } -}; - -} // end namespace internal - -/** \returns the \f$ \ell^p \f$ norm of *this, that is, returns the p-th root of the sum of the p-th powers of the absolute values - * of the coefficients of *this. If \a p is the special value \a Eigen::Infinity, this function returns the \f$ \ell^\infty \f$ - * norm, that is the maximum of the absolute values of the coefficients of *this. - * - * \sa norm() - */ -template -template -inline typename NumTraits::Scalar>::Real -MatrixBase::lpNorm() const -{ - return internal::lpNorm_selector::run(*this); -} - -//---------- implementation of isOrthogonal / isUnitary ---------- - -/** \returns true if *this is approximately orthogonal to \a other, - * within the precision given by \a prec. - * - * Example: \include MatrixBase_isOrthogonal.cpp - * Output: \verbinclude MatrixBase_isOrthogonal.out - */ -template -template -bool MatrixBase::isOrthogonal -(const MatrixBase& other, const RealScalar& prec) const -{ - typename internal::nested::type nested(derived()); - typename internal::nested::type otherNested(other.derived()); - return numext::abs2(nested.dot(otherNested)) <= prec * prec * nested.squaredNorm() * otherNested.squaredNorm(); -} - -/** \returns true if *this is approximately an unitary matrix, - * within the precision given by \a prec. In the case where the \a Scalar - * type is real numbers, a unitary matrix is an orthogonal matrix, whence the name. - * - * \note This can be used to check whether a family of vectors forms an orthonormal basis. - * Indeed, \c m.isUnitary() returns true if and only if the columns (equivalently, the rows) of m form an - * orthonormal basis. - * - * Example: \include MatrixBase_isUnitary.cpp - * Output: \verbinclude MatrixBase_isUnitary.out - */ -template -bool MatrixBase::isUnitary(const RealScalar& prec) const -{ - typename Derived::Nested nested(derived()); - for(Index i = 0; i < cols(); ++i) - { - if(!internal::isApprox(nested.col(i).squaredNorm(), static_cast(1), prec)) - return false; - for(Index j = 0; j < i; ++j) - if(!internal::isMuchSmallerThan(nested.col(i).dot(nested.col(j)), static_cast(1), prec)) - return false; - } - return true; -} - -} // end namespace Eigen - -#endif // EIGEN_DOT_H diff --git a/splinter/src/Core/EigenBase.h b/splinter/src/Core/EigenBase.h deleted file mode 100644 index fadb45852f..0000000000 --- a/splinter/src/Core/EigenBase.h +++ /dev/null @@ -1,131 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Benoit Jacob -// Copyright (C) 2009 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_EIGENBASE_H -#define EIGEN_EIGENBASE_H - -namespace Eigen { - -/** Common base class for all classes T such that MatrixBase has an operator=(T) and a constructor MatrixBase(T). - * - * In other words, an EigenBase object is an object that can be copied into a MatrixBase. - * - * Besides MatrixBase-derived classes, this also includes special matrix classes such as diagonal matrices, etc. - * - * Notice that this class is trivial, it is only used to disambiguate overloaded functions. - * - * \sa \ref TopicClassHierarchy - */ -template struct EigenBase -{ -// typedef typename internal::plain_matrix_type::type PlainObject; - - typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; - - /** \returns a reference to the derived object */ - Derived& derived() { return *static_cast(this); } - /** \returns a const reference to the derived object */ - const Derived& derived() const { return *static_cast(this); } - - inline Derived& const_cast_derived() const - { return *static_cast(const_cast(this)); } - inline const Derived& const_derived() const - { return *static_cast(this); } - - /** \returns the number of rows. \sa cols(), RowsAtCompileTime */ - inline Index rows() const { return derived().rows(); } - /** \returns the number of columns. \sa rows(), ColsAtCompileTime*/ - inline Index cols() const { return derived().cols(); } - /** \returns the number of coefficients, which is rows()*cols(). - * \sa rows(), cols(), SizeAtCompileTime. */ - inline Index size() const { return rows() * cols(); } - - /** \internal Don't use it, but do the equivalent: \code dst = *this; \endcode */ - template inline void evalTo(Dest& dst) const - { derived().evalTo(dst); } - - /** \internal Don't use it, but do the equivalent: \code dst += *this; \endcode */ - template inline void addTo(Dest& dst) const - { - // This is the default implementation, - // derived class can reimplement it in a more optimized way. - typename Dest::PlainObject res(rows(),cols()); - evalTo(res); - dst += res; - } - - /** \internal Don't use it, but do the equivalent: \code dst -= *this; \endcode */ - template inline void subTo(Dest& dst) const - { - // This is the default implementation, - // derived class can reimplement it in a more optimized way. - typename Dest::PlainObject res(rows(),cols()); - evalTo(res); - dst -= res; - } - - /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheRight(*this); \endcode */ - template inline void applyThisOnTheRight(Dest& dst) const - { - // This is the default implementation, - // derived class can reimplement it in a more optimized way. - dst = dst * this->derived(); - } - - /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheLeft(*this); \endcode */ - template inline void applyThisOnTheLeft(Dest& dst) const - { - // This is the default implementation, - // derived class can reimplement it in a more optimized way. - dst = this->derived() * dst; - } - -}; - -/*************************************************************************** -* Implementation of matrix base methods -***************************************************************************/ - -/** \brief Copies the generic expression \a other into *this. - * - * \details The expression must provide a (templated) evalTo(Derived& dst) const - * function which does the actual job. In practice, this allows any user to write - * its own special matrix without having to modify MatrixBase - * - * \returns a reference to *this. - */ -template -template -Derived& DenseBase::operator=(const EigenBase &other) -{ - other.derived().evalTo(derived()); - return derived(); -} - -template -template -Derived& DenseBase::operator+=(const EigenBase &other) -{ - other.derived().addTo(derived()); - return derived(); -} - -template -template -Derived& DenseBase::operator-=(const EigenBase &other) -{ - other.derived().subTo(derived()); - return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_EIGENBASE_H diff --git a/splinter/src/Core/Flagged.h b/splinter/src/Core/Flagged.h deleted file mode 100644 index 1f2955fc1d..0000000000 --- a/splinter/src/Core/Flagged.h +++ /dev/null @@ -1,140 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_FLAGGED_H -#define EIGEN_FLAGGED_H - -namespace Eigen { - -/** \class Flagged - * \ingroup Core_Module - * - * \brief Expression with modified flags - * - * \param ExpressionType the type of the object of which we are modifying the flags - * \param Added the flags added to the expression - * \param Removed the flags removed from the expression (has priority over Added). - * - * This class represents an expression whose flags have been modified. - * It is the return type of MatrixBase::flagged() - * and most of the time this is the only way it is used. - * - * \sa MatrixBase::flagged() - */ - -namespace internal { -template -struct traits > : traits -{ - enum { Flags = (ExpressionType::Flags | Added) & ~Removed }; -}; -} - -template class Flagged - : public MatrixBase > -{ - public: - - typedef MatrixBase Base; - - EIGEN_DENSE_PUBLIC_INTERFACE(Flagged) - typedef typename internal::conditional::ret, - ExpressionType, const ExpressionType&>::type ExpressionTypeNested; - typedef typename ExpressionType::InnerIterator InnerIterator; - - inline Flagged(const ExpressionType& matrix) : m_matrix(matrix) {} - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - inline Index outerStride() const { return m_matrix.outerStride(); } - inline Index innerStride() const { return m_matrix.innerStride(); } - - inline CoeffReturnType coeff(Index row, Index col) const - { - return m_matrix.coeff(row, col); - } - - inline CoeffReturnType coeff(Index index) const - { - return m_matrix.coeff(index); - } - - inline const Scalar& coeffRef(Index row, Index col) const - { - return m_matrix.const_cast_derived().coeffRef(row, col); - } - - inline const Scalar& coeffRef(Index index) const - { - return m_matrix.const_cast_derived().coeffRef(index); - } - - inline Scalar& coeffRef(Index row, Index col) - { - return m_matrix.const_cast_derived().coeffRef(row, col); - } - - inline Scalar& coeffRef(Index index) - { - return m_matrix.const_cast_derived().coeffRef(index); - } - - template - inline const PacketScalar packet(Index row, Index col) const - { - return m_matrix.template packet(row, col); - } - - template - inline void writePacket(Index row, Index col, const PacketScalar& x) - { - m_matrix.const_cast_derived().template writePacket(row, col, x); - } - - template - inline const PacketScalar packet(Index index) const - { - return m_matrix.template packet(index); - } - - template - inline void writePacket(Index index, const PacketScalar& x) - { - m_matrix.const_cast_derived().template writePacket(index, x); - } - - const ExpressionType& _expression() const { return m_matrix; } - - template - typename ExpressionType::PlainObject solveTriangular(const MatrixBase& other) const; - - template - void solveTriangularInPlace(const MatrixBase& other) const; - - protected: - ExpressionTypeNested m_matrix; -}; - -/** \returns an expression of *this with added and removed flags - * - * This is mostly for internal use. - * - * \sa class Flagged - */ -template -template -inline const Flagged -DenseBase::flagged() const -{ - return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_FLAGGED_H diff --git a/splinter/src/Core/ForceAlignedAccess.h b/splinter/src/Core/ForceAlignedAccess.h deleted file mode 100644 index 807c7a2934..0000000000 --- a/splinter/src/Core/ForceAlignedAccess.h +++ /dev/null @@ -1,146 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_FORCEALIGNEDACCESS_H -#define EIGEN_FORCEALIGNEDACCESS_H - -namespace Eigen { - -/** \class ForceAlignedAccess - * \ingroup Core_Module - * - * \brief Enforce aligned packet loads and stores regardless of what is requested - * - * \param ExpressionType the type of the object of which we are forcing aligned packet access - * - * This class is the return type of MatrixBase::forceAlignedAccess() - * and most of the time this is the only way it is used. - * - * \sa MatrixBase::forceAlignedAccess() - */ - -namespace internal { -template -struct traits > : public traits -{}; -} - -template class ForceAlignedAccess - : public internal::dense_xpr_base< ForceAlignedAccess >::type -{ - public: - - typedef typename internal::dense_xpr_base::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(ForceAlignedAccess) - - inline ForceAlignedAccess(const ExpressionType& matrix) : m_expression(matrix) {} - - inline Index rows() const { return m_expression.rows(); } - inline Index cols() const { return m_expression.cols(); } - inline Index outerStride() const { return m_expression.outerStride(); } - inline Index innerStride() const { return m_expression.innerStride(); } - - inline const CoeffReturnType coeff(Index row, Index col) const - { - return m_expression.coeff(row, col); - } - - inline Scalar& coeffRef(Index row, Index col) - { - return m_expression.const_cast_derived().coeffRef(row, col); - } - - inline const CoeffReturnType coeff(Index index) const - { - return m_expression.coeff(index); - } - - inline Scalar& coeffRef(Index index) - { - return m_expression.const_cast_derived().coeffRef(index); - } - - template - inline const PacketScalar packet(Index row, Index col) const - { - return m_expression.template packet(row, col); - } - - template - inline void writePacket(Index row, Index col, const PacketScalar& x) - { - m_expression.const_cast_derived().template writePacket(row, col, x); - } - - template - inline const PacketScalar packet(Index index) const - { - return m_expression.template packet(index); - } - - template - inline void writePacket(Index index, const PacketScalar& x) - { - m_expression.const_cast_derived().template writePacket(index, x); - } - - operator const ExpressionType&() const { return m_expression; } - - protected: - const ExpressionType& m_expression; - - private: - ForceAlignedAccess& operator=(const ForceAlignedAccess&); -}; - -/** \returns an expression of *this with forced aligned access - * \sa forceAlignedAccessIf(),class ForceAlignedAccess - */ -template -inline const ForceAlignedAccess -MatrixBase::forceAlignedAccess() const -{ - return ForceAlignedAccess(derived()); -} - -/** \returns an expression of *this with forced aligned access - * \sa forceAlignedAccessIf(), class ForceAlignedAccess - */ -template -inline ForceAlignedAccess -MatrixBase::forceAlignedAccess() -{ - return ForceAlignedAccess(derived()); -} - -/** \returns an expression of *this with forced aligned access if \a Enable is true. - * \sa forceAlignedAccess(), class ForceAlignedAccess - */ -template -template -inline typename internal::add_const_on_value_type,Derived&>::type>::type -MatrixBase::forceAlignedAccessIf() const -{ - return derived(); -} - -/** \returns an expression of *this with forced aligned access if \a Enable is true. - * \sa forceAlignedAccess(), class ForceAlignedAccess - */ -template -template -inline typename internal::conditional,Derived&>::type -MatrixBase::forceAlignedAccessIf() -{ - return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_FORCEALIGNEDACCESS_H diff --git a/splinter/src/Core/Functors.h b/splinter/src/Core/Functors.h deleted file mode 100644 index 5f14c6587e..0000000000 --- a/splinter/src/Core/Functors.h +++ /dev/null @@ -1,1026 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_FUNCTORS_H -#define EIGEN_FUNCTORS_H - -namespace Eigen { - -namespace internal { - -// associative functors: - -/** \internal - * \brief Template functor to compute the sum of two scalars - * - * \sa class CwiseBinaryOp, MatrixBase::operator+, class VectorwiseOp, MatrixBase::sum() - */ -template struct scalar_sum_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_sum_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { return a + b; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::padd(a,b); } - template - EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const - { return internal::predux(a); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasAdd - }; -}; - -/** \internal - * \brief Template functor to compute the product of two scalars - * - * \sa class CwiseBinaryOp, Cwise::operator*(), class VectorwiseOp, MatrixBase::redux() - */ -template struct scalar_product_op { - enum { - // TODO vectorize mixed product - Vectorizable = is_same::value && packet_traits::HasMul && packet_traits::HasMul - }; - typedef typename scalar_product_traits::ReturnType result_type; - EIGEN_EMPTY_STRUCT_CTOR(scalar_product_op) - EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a * b; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pmul(a,b); } - template - EIGEN_STRONG_INLINE const result_type predux(const Packet& a) const - { return internal::predux_mul(a); } -}; -template -struct functor_traits > { - enum { - Cost = (NumTraits::MulCost + NumTraits::MulCost)/2, // rough estimate! - PacketAccess = scalar_product_op::Vectorizable - }; -}; - -/** \internal - * \brief Template functor to compute the conjugate product of two scalars - * - * This is a short cut for conj(x) * y which is needed for optimization purpose; in Eigen2 support mode, this becomes x * conj(y) - */ -template struct scalar_conj_product_op { - - enum { - Conj = NumTraits::IsComplex - }; - - typedef typename scalar_product_traits::ReturnType result_type; - - EIGEN_EMPTY_STRUCT_CTOR(scalar_conj_product_op) - EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const - { return conj_helper().pmul(a,b); } - - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return conj_helper().pmul(a,b); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::MulCost, - PacketAccess = internal::is_same::value && packet_traits::HasMul - }; -}; - -/** \internal - * \brief Template functor to compute the min of two scalars - * - * \sa class CwiseBinaryOp, MatrixBase::cwiseMin, class VectorwiseOp, MatrixBase::minCoeff() - */ -template struct scalar_min_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_min_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { using std::min; return (min)(a, b); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pmin(a,b); } - template - EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const - { return internal::predux_min(a); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasMin - }; -}; - -/** \internal - * \brief Template functor to compute the max of two scalars - * - * \sa class CwiseBinaryOp, MatrixBase::cwiseMax, class VectorwiseOp, MatrixBase::maxCoeff() - */ -template struct scalar_max_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_max_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { using std::max; return (max)(a, b); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pmax(a,b); } - template - EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const - { return internal::predux_max(a); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasMax - }; -}; - -/** \internal - * \brief Template functor to compute the hypot of two scalars - * - * \sa MatrixBase::stableNorm(), class Redux - */ -template struct scalar_hypot_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_hypot_op) -// typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& _x, const Scalar& _y) const - { - using std::max; - using std::min; - using std::sqrt; - Scalar p = (max)(_x, _y); - Scalar q = (min)(_x, _y); - Scalar qp = q/p; - return p * sqrt(Scalar(1) + qp*qp); - } -}; -template -struct functor_traits > { - enum { Cost = 5 * NumTraits::MulCost, PacketAccess=0 }; -}; - -/** \internal - * \brief Template functor to compute the pow of two scalars - */ -template struct scalar_binary_pow_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_binary_pow_op) - inline Scalar operator() (const Scalar& a, const OtherScalar& b) const { return numext::pow(a, b); } -}; -template -struct functor_traits > { - enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false }; -}; - -// other binary functors: - -/** \internal - * \brief Template functor to compute the difference of two scalars - * - * \sa class CwiseBinaryOp, MatrixBase::operator- - */ -template struct scalar_difference_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_difference_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { return a - b; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::psub(a,b); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasSub - }; -}; - -/** \internal - * \brief Template functor to compute the quotient of two scalars - * - * \sa class CwiseBinaryOp, Cwise::operator/() - */ -template struct scalar_quotient_op { - enum { - // TODO vectorize mixed product - Vectorizable = is_same::value && packet_traits::HasDiv && packet_traits::HasDiv - }; - typedef typename scalar_product_traits::ReturnType result_type; - EIGEN_EMPTY_STRUCT_CTOR(scalar_quotient_op) - EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a / b; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pdiv(a,b); } -}; -template -struct functor_traits > { - enum { - Cost = (NumTraits::MulCost + NumTraits::MulCost), // rough estimate! - PacketAccess = scalar_quotient_op::Vectorizable - }; -}; - - - -/** \internal - * \brief Template functor to compute the and of two booleans - * - * \sa class CwiseBinaryOp, ArrayBase::operator&& - */ -struct scalar_boolean_and_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_boolean_and_op) - EIGEN_STRONG_INLINE bool operator() (const bool& a, const bool& b) const { return a && b; } -}; -template<> struct functor_traits { - enum { - Cost = NumTraits::AddCost, - PacketAccess = false - }; -}; - -/** \internal - * \brief Template functor to compute the or of two booleans - * - * \sa class CwiseBinaryOp, ArrayBase::operator|| - */ -struct scalar_boolean_or_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_boolean_or_op) - EIGEN_STRONG_INLINE bool operator() (const bool& a, const bool& b) const { return a || b; } -}; -template<> struct functor_traits { - enum { - Cost = NumTraits::AddCost, - PacketAccess = false - }; -}; - -/** \internal - * \brief Template functors for comparison of two scalars - * \todo Implement packet-comparisons - */ -template struct scalar_cmp_op; - -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = false - }; -}; - -template -struct result_of(Scalar,Scalar)> { - typedef bool type; -}; - - -template struct scalar_cmp_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) - EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a==b;} -}; -template struct scalar_cmp_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) - EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a struct scalar_cmp_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) - EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a<=b;} -}; -template struct scalar_cmp_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) - EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return !(a<=b || b<=a);} -}; -template struct scalar_cmp_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) - EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a!=b;} -}; - -// unary functors: - -/** \internal - * \brief Template functor to compute the opposite of a scalar - * - * \sa class CwiseUnaryOp, MatrixBase::operator- - */ -template struct scalar_opposite_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_opposite_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { return -a; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pnegate(a); } -}; -template -struct functor_traits > -{ enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasNegate }; -}; - -/** \internal - * \brief Template functor to compute the absolute value of a scalar - * - * \sa class CwiseUnaryOp, Cwise::abs - */ -template struct scalar_abs_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_abs_op) - typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { using std::abs; return abs(a); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pabs(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasAbs - }; -}; - -/** \internal - * \brief Template functor to compute the squared absolute value of a scalar - * - * \sa class CwiseUnaryOp, Cwise::abs2 - */ -template struct scalar_abs2_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_abs2_op) - typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { return numext::abs2(a); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pmul(a,a); } -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasAbs2 }; }; - -/** \internal - * \brief Template functor to compute the conjugate of a complex value - * - * \sa class CwiseUnaryOp, MatrixBase::conjugate() - */ -template struct scalar_conjugate_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_conjugate_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { using numext::conj; return conj(a); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const { return internal::pconj(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = NumTraits::IsComplex ? NumTraits::AddCost : 0, - PacketAccess = packet_traits::HasConj - }; -}; - -/** \internal - * \brief Template functor to cast a scalar to another type - * - * \sa class CwiseUnaryOp, MatrixBase::cast() - */ -template -struct scalar_cast_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cast_op) - typedef NewType result_type; - EIGEN_STRONG_INLINE const NewType operator() (const Scalar& a) const { return cast(a); } -}; -template -struct functor_traits > -{ enum { Cost = is_same::value ? 0 : NumTraits::AddCost, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to extract the real part of a complex - * - * \sa class CwiseUnaryOp, MatrixBase::real() - */ -template -struct scalar_real_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_real_op) - typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return numext::real(a); } -}; -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to extract the imaginary part of a complex - * - * \sa class CwiseUnaryOp, MatrixBase::imag() - */ -template -struct scalar_imag_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_imag_op) - typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return numext::imag(a); } -}; -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to extract the real part of a complex as a reference - * - * \sa class CwiseUnaryOp, MatrixBase::real() - */ -template -struct scalar_real_ref_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_real_ref_op) - typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE result_type& operator() (const Scalar& a) const { return numext::real_ref(*const_cast(&a)); } -}; -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to extract the imaginary part of a complex as a reference - * - * \sa class CwiseUnaryOp, MatrixBase::imag() - */ -template -struct scalar_imag_ref_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_imag_ref_op) - typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE result_type& operator() (const Scalar& a) const { return numext::imag_ref(*const_cast(&a)); } -}; -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -/** \internal - * - * \brief Template functor to compute the exponential of a scalar - * - * \sa class CwiseUnaryOp, Cwise::exp() - */ -template struct scalar_exp_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_exp_op) - inline const Scalar operator() (const Scalar& a) const { using std::exp; return exp(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::pexp(a); } -}; -template -struct functor_traits > -{ enum { Cost = 5 * NumTraits::MulCost, PacketAccess = packet_traits::HasExp }; }; - -/** \internal - * - * \brief Template functor to compute the logarithm of a scalar - * - * \sa class CwiseUnaryOp, Cwise::log() - */ -template struct scalar_log_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_log_op) - inline const Scalar operator() (const Scalar& a) const { using std::log; return log(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::plog(a); } -}; -template -struct functor_traits > -{ enum { Cost = 5 * NumTraits::MulCost, PacketAccess = packet_traits::HasLog }; }; - -/** \internal - * \brief Template functor to multiply a scalar by a fixed other one - * - * \sa class CwiseUnaryOp, MatrixBase::operator*, MatrixBase::operator/ - */ -/* NOTE why doing the pset1() in packetOp *is* an optimization ? - * indeed it seems better to declare m_other as a Packet and do the pset1() once - * in the constructor. However, in practice: - * - GCC does not like m_other as a Packet and generate a load every time it needs it - * - on the other hand GCC is able to moves the pset1() outside the loop :) - * - simpler code ;) - * (ICC and gcc 4.4 seems to perform well in both cases, the issue is visible with y = a*x + b*y) - */ -template -struct scalar_multiple_op { - typedef typename packet_traits::type Packet; - // FIXME default copy constructors seems bugged with std::complex<> - EIGEN_STRONG_INLINE scalar_multiple_op(const scalar_multiple_op& other) : m_other(other.m_other) { } - EIGEN_STRONG_INLINE scalar_multiple_op(const Scalar& other) : m_other(other) { } - EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a) const { return a * m_other; } - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pmul(a, pset1(m_other)); } - typename add_const_on_value_type::Nested>::type m_other; -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; - -template -struct scalar_multiple2_op { - typedef typename scalar_product_traits::ReturnType result_type; - EIGEN_STRONG_INLINE scalar_multiple2_op(const scalar_multiple2_op& other) : m_other(other.m_other) { } - EIGEN_STRONG_INLINE scalar_multiple2_op(const Scalar2& other) : m_other(other) { } - EIGEN_STRONG_INLINE result_type operator() (const Scalar1& a) const { return a * m_other; } - typename add_const_on_value_type::Nested>::type m_other; -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to divide a scalar by a fixed other one - * - * This functor is used to implement the quotient of a matrix by - * a scalar where the scalar type is not necessarily a floating point type. - * - * \sa class CwiseUnaryOp, MatrixBase::operator/ - */ -template -struct scalar_quotient1_op { - typedef typename packet_traits::type Packet; - // FIXME default copy constructors seems bugged with std::complex<> - EIGEN_STRONG_INLINE scalar_quotient1_op(const scalar_quotient1_op& other) : m_other(other.m_other) { } - EIGEN_STRONG_INLINE scalar_quotient1_op(const Scalar& other) : m_other(other) {} - EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a) const { return a / m_other; } - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pdiv(a, pset1(m_other)); } - typename add_const_on_value_type::Nested>::type m_other; -}; -template -struct functor_traits > -{ enum { Cost = 2 * NumTraits::MulCost, PacketAccess = packet_traits::HasDiv }; }; - -// nullary functors - -template -struct scalar_constant_op { - typedef typename packet_traits::type Packet; - EIGEN_STRONG_INLINE scalar_constant_op(const scalar_constant_op& other) : m_other(other.m_other) { } - EIGEN_STRONG_INLINE scalar_constant_op(const Scalar& other) : m_other(other) { } - template - EIGEN_STRONG_INLINE const Scalar operator() (Index, Index = 0) const { return m_other; } - template - EIGEN_STRONG_INLINE const Packet packetOp(Index, Index = 0) const { return internal::pset1(m_other); } - const Scalar m_other; -}; -template -struct functor_traits > -// FIXME replace this packet test by a safe one -{ enum { Cost = 1, PacketAccess = packet_traits::Vectorizable, IsRepeatable = true }; }; - -template struct scalar_identity_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_identity_op) - template - EIGEN_STRONG_INLINE const Scalar operator() (Index row, Index col) const { return row==col ? Scalar(1) : Scalar(0); } -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = false, IsRepeatable = true }; }; - -template struct linspaced_op_impl; - -// linear access for packet ops: -// 1) initialization -// base = [low, ..., low] + ([step, ..., step] * [-size, ..., 0]) -// 2) each step (where size is 1 for coeff access or PacketSize for packet access) -// base += [size*step, ..., size*step] -// -// TODO: Perhaps it's better to initialize lazily (so not in the constructor but in packetOp) -// in order to avoid the padd() in operator() ? -template -struct linspaced_op_impl -{ - typedef typename packet_traits::type Packet; - - linspaced_op_impl(const Scalar& low, const Scalar& step) : - m_low(low), m_step(step), - m_packetStep(pset1(packet_traits::size*step)), - m_base(padd(pset1(low), pmul(pset1(step),plset(-packet_traits::size)))) {} - - template - EIGEN_STRONG_INLINE const Scalar operator() (Index i) const - { - m_base = padd(m_base, pset1(m_step)); - return m_low+Scalar(i)*m_step; - } - - template - EIGEN_STRONG_INLINE const Packet packetOp(Index) const { return m_base = padd(m_base,m_packetStep); } - - const Scalar m_low; - const Scalar m_step; - const Packet m_packetStep; - mutable Packet m_base; -}; - -// random access for packet ops: -// 1) each step -// [low, ..., low] + ( [step, ..., step] * ( [i, ..., i] + [0, ..., size] ) ) -template -struct linspaced_op_impl -{ - typedef typename packet_traits::type Packet; - - linspaced_op_impl(const Scalar& low, const Scalar& step) : - m_low(low), m_step(step), - m_lowPacket(pset1(m_low)), m_stepPacket(pset1(m_step)), m_interPacket(plset(0)) {} - - template - EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return m_low+i*m_step; } - - template - EIGEN_STRONG_INLINE const Packet packetOp(Index i) const - { return internal::padd(m_lowPacket, pmul(m_stepPacket, padd(pset1(Scalar(i)),m_interPacket))); } - - const Scalar m_low; - const Scalar m_step; - const Packet m_lowPacket; - const Packet m_stepPacket; - const Packet m_interPacket; -}; - -// ----- Linspace functor ---------------------------------------------------------------- - -// Forward declaration (we default to random access which does not really give -// us a speed gain when using packet access but it allows to use the functor in -// nested expressions). -template struct linspaced_op; -template struct functor_traits< linspaced_op > -{ enum { Cost = 1, PacketAccess = packet_traits::HasSetLinear, IsRepeatable = true }; }; -template struct linspaced_op -{ - typedef typename packet_traits::type Packet; - linspaced_op(const Scalar& low, const Scalar& high, DenseIndex num_steps) : impl((num_steps==1 ? high : low), (num_steps==1 ? Scalar() : (high-low)/Scalar(num_steps-1))) {} - - template - EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return impl(i); } - - // We need this function when assigning e.g. a RowVectorXd to a MatrixXd since - // there row==0 and col is used for the actual iteration. - template - EIGEN_STRONG_INLINE const Scalar operator() (Index row, Index col) const - { - eigen_assert(col==0 || row==0); - return impl(col + row); - } - - template - EIGEN_STRONG_INLINE const Packet packetOp(Index i) const { return impl.packetOp(i); } - - // We need this function when assigning e.g. a RowVectorXd to a MatrixXd since - // there row==0 and col is used for the actual iteration. - template - EIGEN_STRONG_INLINE const Packet packetOp(Index row, Index col) const - { - eigen_assert(col==0 || row==0); - return impl.packetOp(col + row); - } - - // This proxy object handles the actual required temporaries, the different - // implementations (random vs. sequential access) as well as the - // correct piping to size 2/4 packet operations. - const linspaced_op_impl impl; -}; - -// all functors allow linear access, except scalar_identity_op. So we fix here a quick meta -// to indicate whether a functor allows linear access, just always answering 'yes' except for -// scalar_identity_op. -// FIXME move this to functor_traits adding a functor_default -template struct functor_has_linear_access { enum { ret = 1 }; }; -template struct functor_has_linear_access > { enum { ret = 0 }; }; - -// In Eigen, any binary op (Product, CwiseBinaryOp) require the Lhs and Rhs to have the same scalar type, except for multiplication -// where the mixing of different types is handled by scalar_product_traits -// In particular, real * complex is allowed. -// FIXME move this to functor_traits adding a functor_default -template struct functor_is_product_like { enum { ret = 0 }; }; -template struct functor_is_product_like > { enum { ret = 1 }; }; -template struct functor_is_product_like > { enum { ret = 1 }; }; -template struct functor_is_product_like > { enum { ret = 1 }; }; - - -/** \internal - * \brief Template functor to add a scalar to a fixed other one - * \sa class CwiseUnaryOp, Array::operator+ - */ -/* If you wonder why doing the pset1() in packetOp() is an optimization check scalar_multiple_op */ -template -struct scalar_add_op { - typedef typename packet_traits::type Packet; - // FIXME default copy constructors seems bugged with std::complex<> - inline scalar_add_op(const scalar_add_op& other) : m_other(other.m_other) { } - inline scalar_add_op(const Scalar& other) : m_other(other) { } - inline Scalar operator() (const Scalar& a) const { return a + m_other; } - inline const Packet packetOp(const Packet& a) const - { return internal::padd(a, pset1(m_other)); } - const Scalar m_other; -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasAdd }; }; - -/** \internal - * \brief Template functor to compute the square root of a scalar - * \sa class CwiseUnaryOp, Cwise::sqrt() - */ -template struct scalar_sqrt_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_sqrt_op) - inline const Scalar operator() (const Scalar& a) const { using std::sqrt; return sqrt(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::psqrt(a); } -}; -template -struct functor_traits > -{ enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasSqrt - }; -}; - -/** \internal - * \brief Template functor to compute the cosine of a scalar - * \sa class CwiseUnaryOp, ArrayBase::cos() - */ -template struct scalar_cos_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cos_op) - inline Scalar operator() (const Scalar& a) const { using std::cos; return cos(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::pcos(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasCos - }; -}; - -/** \internal - * \brief Template functor to compute the sine of a scalar - * \sa class CwiseUnaryOp, ArrayBase::sin() - */ -template struct scalar_sin_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_sin_op) - inline const Scalar operator() (const Scalar& a) const { using std::sin; return sin(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::psin(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasSin - }; -}; - - -/** \internal - * \brief Template functor to compute the tan of a scalar - * \sa class CwiseUnaryOp, ArrayBase::tan() - */ -template struct scalar_tan_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_tan_op) - inline const Scalar operator() (const Scalar& a) const { using std::tan; return tan(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::ptan(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasTan - }; -}; - -/** \internal - * \brief Template functor to compute the arc cosine of a scalar - * \sa class CwiseUnaryOp, ArrayBase::acos() - */ -template struct scalar_acos_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_acos_op) - inline const Scalar operator() (const Scalar& a) const { using std::acos; return acos(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::pacos(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasACos - }; -}; - -/** \internal - * \brief Template functor to compute the arc sine of a scalar - * \sa class CwiseUnaryOp, ArrayBase::asin() - */ -template struct scalar_asin_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_asin_op) - inline const Scalar operator() (const Scalar& a) const { using std::asin; return asin(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::pasin(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasASin - }; -}; - -/** \internal - * \brief Template functor to raise a scalar to a power - * \sa class CwiseUnaryOp, Cwise::pow - */ -template -struct scalar_pow_op { - // FIXME default copy constructors seems bugged with std::complex<> - inline scalar_pow_op(const scalar_pow_op& other) : m_exponent(other.m_exponent) { } - inline scalar_pow_op(const Scalar& exponent) : m_exponent(exponent) {} - inline Scalar operator() (const Scalar& a) const { return numext::pow(a, m_exponent); } - const Scalar m_exponent; -}; -template -struct functor_traits > -{ enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to compute the quotient between a scalar and array entries. - * \sa class CwiseUnaryOp, Cwise::inverse() - */ -template -struct scalar_inverse_mult_op { - scalar_inverse_mult_op(const Scalar& other) : m_other(other) {} - inline Scalar operator() (const Scalar& a) const { return m_other / a; } - template - inline const Packet packetOp(const Packet& a) const - { return internal::pdiv(pset1(m_other),a); } - Scalar m_other; -}; - -/** \internal - * \brief Template functor to compute the inverse of a scalar - * \sa class CwiseUnaryOp, Cwise::inverse() - */ -template -struct scalar_inverse_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_inverse_op) - inline Scalar operator() (const Scalar& a) const { return Scalar(1)/a; } - template - inline const Packet packetOp(const Packet& a) const - { return internal::pdiv(pset1(Scalar(1)),a); } -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasDiv }; }; - -/** \internal - * \brief Template functor to compute the square of a scalar - * \sa class CwiseUnaryOp, Cwise::square() - */ -template -struct scalar_square_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_square_op) - inline Scalar operator() (const Scalar& a) const { return a*a; } - template - inline const Packet packetOp(const Packet& a) const - { return internal::pmul(a,a); } -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; - -/** \internal - * \brief Template functor to compute the cube of a scalar - * \sa class CwiseUnaryOp, Cwise::cube() - */ -template -struct scalar_cube_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cube_op) - inline Scalar operator() (const Scalar& a) const { return a*a*a; } - template - inline const Packet packetOp(const Packet& a) const - { return internal::pmul(a,pmul(a,a)); } -}; -template -struct functor_traits > -{ enum { Cost = 2*NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; - -// default functor traits for STL functors: - -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = functor_traits::Cost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = functor_traits::Cost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1 + functor_traits::Cost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1 + functor_traits::Cost, PacketAccess = false }; }; - -#ifdef EIGEN_STDEXT_SUPPORT - -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -template -struct functor_traits > > -{ enum { Cost = 0, PacketAccess = false }; }; - -template -struct functor_traits > > -{ enum { Cost = 0, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = functor_traits::Cost + functor_traits::Cost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = functor_traits::Cost + functor_traits::Cost + functor_traits::Cost, PacketAccess = false }; }; - -#endif // EIGEN_STDEXT_SUPPORT - -// allow to add new functors and specializations of functor_traits from outside Eigen. -// this macro is really needed because functor_traits must be specialized after it is declared but before it is used... -#ifdef EIGEN_FUNCTORS_PLUGIN -#include EIGEN_FUNCTORS_PLUGIN -#endif - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_FUNCTORS_H diff --git a/splinter/src/Core/Fuzzy.h b/splinter/src/Core/Fuzzy.h deleted file mode 100644 index fe63bd2984..0000000000 --- a/splinter/src/Core/Fuzzy.h +++ /dev/null @@ -1,150 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2008 Benoit Jacob -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_FUZZY_H -#define EIGEN_FUZZY_H - -namespace Eigen { - -namespace internal -{ - -template::IsInteger> -struct isApprox_selector -{ - static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar& prec) - { - using std::min; - typename internal::nested::type nested(x); - typename internal::nested::type otherNested(y); - return (nested - otherNested).cwiseAbs2().sum() <= prec * prec * (min)(nested.cwiseAbs2().sum(), otherNested.cwiseAbs2().sum()); - } -}; - -template -struct isApprox_selector -{ - static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar&) - { - return x.matrix() == y.matrix(); - } -}; - -template::IsInteger> -struct isMuchSmallerThan_object_selector -{ - static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar& prec) - { - return x.cwiseAbs2().sum() <= numext::abs2(prec) * y.cwiseAbs2().sum(); - } -}; - -template -struct isMuchSmallerThan_object_selector -{ - static bool run(const Derived& x, const OtherDerived&, const typename Derived::RealScalar&) - { - return x.matrix() == Derived::Zero(x.rows(), x.cols()).matrix(); - } -}; - -template::IsInteger> -struct isMuchSmallerThan_scalar_selector -{ - static bool run(const Derived& x, const typename Derived::RealScalar& y, const typename Derived::RealScalar& prec) - { - return x.cwiseAbs2().sum() <= numext::abs2(prec * y); - } -}; - -template -struct isMuchSmallerThan_scalar_selector -{ - static bool run(const Derived& x, const typename Derived::RealScalar&, const typename Derived::RealScalar&) - { - return x.matrix() == Derived::Zero(x.rows(), x.cols()).matrix(); - } -}; - -} // end namespace internal - - -/** \returns \c true if \c *this is approximately equal to \a other, within the precision - * determined by \a prec. - * - * \note The fuzzy compares are done multiplicatively. Two vectors \f$ v \f$ and \f$ w \f$ - * are considered to be approximately equal within precision \f$ p \f$ if - * \f[ \Vert v - w \Vert \leqslant p\,\min(\Vert v\Vert, \Vert w\Vert). \f] - * For matrices, the comparison is done using the Hilbert-Schmidt norm (aka Frobenius norm - * L2 norm). - * - * \note Because of the multiplicativeness of this comparison, one can't use this function - * to check whether \c *this is approximately equal to the zero matrix or vector. - * Indeed, \c isApprox(zero) returns false unless \c *this itself is exactly the zero matrix - * or vector. If you want to test whether \c *this is zero, use internal::isMuchSmallerThan(const - * RealScalar&, RealScalar) instead. - * - * \sa internal::isMuchSmallerThan(const RealScalar&, RealScalar) const - */ -template -template -bool DenseBase::isApprox( - const DenseBase& other, - const RealScalar& prec -) const -{ - return internal::isApprox_selector::run(derived(), other.derived(), prec); -} - -/** \returns \c true if the norm of \c *this is much smaller than \a other, - * within the precision determined by \a prec. - * - * \note The fuzzy compares are done multiplicatively. A vector \f$ v \f$ is - * considered to be much smaller than \f$ x \f$ within precision \f$ p \f$ if - * \f[ \Vert v \Vert \leqslant p\,\vert x\vert. \f] - * - * For matrices, the comparison is done using the Hilbert-Schmidt norm. For this reason, - * the value of the reference scalar \a other should come from the Hilbert-Schmidt norm - * of a reference matrix of same dimensions. - * - * \sa isApprox(), isMuchSmallerThan(const DenseBase&, RealScalar) const - */ -template -bool DenseBase::isMuchSmallerThan( - const typename NumTraits::Real& other, - const RealScalar& prec -) const -{ - return internal::isMuchSmallerThan_scalar_selector::run(derived(), other, prec); -} - -/** \returns \c true if the norm of \c *this is much smaller than the norm of \a other, - * within the precision determined by \a prec. - * - * \note The fuzzy compares are done multiplicatively. A vector \f$ v \f$ is - * considered to be much smaller than a vector \f$ w \f$ within precision \f$ p \f$ if - * \f[ \Vert v \Vert \leqslant p\,\Vert w\Vert. \f] - * For matrices, the comparison is done using the Hilbert-Schmidt norm. - * - * \sa isApprox(), isMuchSmallerThan(const RealScalar&, RealScalar) const - */ -template -template -bool DenseBase::isMuchSmallerThan( - const DenseBase& other, - const RealScalar& prec -) const -{ - return internal::isMuchSmallerThan_object_selector::run(derived(), other.derived(), prec); -} - -} // end namespace Eigen - -#endif // EIGEN_FUZZY_H diff --git a/splinter/src/Core/GeneralProduct.h b/splinter/src/Core/GeneralProduct.h deleted file mode 100644 index 29ac522d2e..0000000000 --- a/splinter/src/Core/GeneralProduct.h +++ /dev/null @@ -1,638 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2008 Benoit Jacob -// Copyright (C) 2008-2011 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_GENERAL_PRODUCT_H -#define EIGEN_GENERAL_PRODUCT_H - -namespace Eigen { - -/** \class GeneralProduct - * \ingroup Core_Module - * - * \brief Expression of the product of two general matrices or vectors - * - * \param LhsNested the type used to store the left-hand side - * \param RhsNested the type used to store the right-hand side - * \param ProductMode the type of the product - * - * This class represents an expression of the product of two general matrices. - * We call a general matrix, a dense matrix with full storage. For instance, - * This excludes triangular, selfadjoint, and sparse matrices. - * It is the return type of the operator* between general matrices. Its template - * arguments are determined automatically by ProductReturnType. Therefore, - * GeneralProduct should never be used direclty. To determine the result type of a - * function which involves a matrix product, use ProductReturnType::Type. - * - * \sa ProductReturnType, MatrixBase::operator*(const MatrixBase&) - */ -template::value> -class GeneralProduct; - -enum { - Large = 2, - Small = 3 -}; - -namespace internal { - -template struct product_type_selector; - -template struct product_size_category -{ - enum { is_large = MaxSize == Dynamic || - Size >= EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD, - value = is_large ? Large - : Size == 1 ? 1 - : Small - }; -}; - -template struct product_type -{ - typedef typename remove_all::type _Lhs; - typedef typename remove_all::type _Rhs; - enum { - MaxRows = _Lhs::MaxRowsAtCompileTime, - Rows = _Lhs::RowsAtCompileTime, - MaxCols = _Rhs::MaxColsAtCompileTime, - Cols = _Rhs::ColsAtCompileTime, - MaxDepth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::MaxColsAtCompileTime, - _Rhs::MaxRowsAtCompileTime), - Depth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::ColsAtCompileTime, - _Rhs::RowsAtCompileTime), - LargeThreshold = EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD - }; - - // the splitting into different lines of code here, introducing the _select enums and the typedef below, - // is to work around an internal compiler error with gcc 4.1 and 4.2. -private: - enum { - rows_select = product_size_category::value, - cols_select = product_size_category::value, - depth_select = product_size_category::value - }; - typedef product_type_selector selector; - -public: - enum { - value = selector::ret - }; -#ifdef EIGEN_DEBUG_PRODUCT - static void debug() - { - EIGEN_DEBUG_VAR(Rows); - EIGEN_DEBUG_VAR(Cols); - EIGEN_DEBUG_VAR(Depth); - EIGEN_DEBUG_VAR(rows_select); - EIGEN_DEBUG_VAR(cols_select); - EIGEN_DEBUG_VAR(depth_select); - EIGEN_DEBUG_VAR(value); - } -#endif -}; - - -/* The following allows to select the kind of product at compile time - * based on the three dimensions of the product. - * This is a compile time mapping from {1,Small,Large}^3 -> {product types} */ -// FIXME I'm not sure the current mapping is the ideal one. -template struct product_type_selector { enum { ret = OuterProduct }; }; -template struct product_type_selector<1, 1, Depth> { enum { ret = InnerProduct }; }; -template<> struct product_type_selector<1, 1, 1> { enum { ret = InnerProduct }; }; -template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; -template<> struct product_type_selector<1, Small,Small> { enum { ret = CoeffBasedProductMode }; }; -template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; -template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; -template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; -template<> struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; -template<> struct product_type_selector<1, Large,Small> { enum { ret = CoeffBasedProductMode }; }; -template<> struct product_type_selector<1, Large,Large> { enum { ret = GemvProduct }; }; -template<> struct product_type_selector<1, Small,Large> { enum { ret = CoeffBasedProductMode }; }; -template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; -template<> struct product_type_selector { enum { ret = GemvProduct }; }; -template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; -template<> struct product_type_selector { enum { ret = GemmProduct }; }; -template<> struct product_type_selector { enum { ret = GemmProduct }; }; -template<> struct product_type_selector { enum { ret = GemmProduct }; }; -template<> struct product_type_selector { enum { ret = GemmProduct }; }; -template<> struct product_type_selector { enum { ret = GemmProduct }; }; -template<> struct product_type_selector { enum { ret = GemmProduct }; }; -template<> struct product_type_selector { enum { ret = GemmProduct }; }; - -} // end namespace internal - -/** \class ProductReturnType - * \ingroup Core_Module - * - * \brief Helper class to get the correct and optimized returned type of operator* - * - * \param Lhs the type of the left-hand side - * \param Rhs the type of the right-hand side - * \param ProductMode the type of the product (determined automatically by internal::product_mode) - * - * This class defines the typename Type representing the optimized product expression - * between two matrix expressions. In practice, using ProductReturnType::Type - * is the recommended way to define the result type of a function returning an expression - * which involve a matrix product. The class Product should never be - * used directly. - * - * \sa class Product, MatrixBase::operator*(const MatrixBase&) - */ -template -struct ProductReturnType -{ - // TODO use the nested type to reduce instanciations ???? -// typedef typename internal::nested::type LhsNested; -// typedef typename internal::nested::type RhsNested; - - typedef GeneralProduct Type; -}; - -template -struct ProductReturnType -{ - typedef typename internal::nested::type >::type LhsNested; - typedef typename internal::nested::type >::type RhsNested; - typedef CoeffBasedProduct Type; -}; - -template -struct ProductReturnType -{ - typedef typename internal::nested::type >::type LhsNested; - typedef typename internal::nested::type >::type RhsNested; - typedef CoeffBasedProduct Type; -}; - -// this is a workaround for sun CC -template -struct LazyProductReturnType : public ProductReturnType -{}; - -/*********************************************************************** -* Implementation of Inner Vector Vector Product -***********************************************************************/ - -// FIXME : maybe the "inner product" could return a Scalar -// instead of a 1x1 matrix ?? -// Pro: more natural for the user -// Cons: this could be a problem if in a meta unrolled algorithm a matrix-matrix -// product ends up to a row-vector times col-vector product... To tackle this use -// case, we could have a specialization for Block with: operator=(Scalar x); - -namespace internal { - -template -struct traits > - : traits::ReturnType,1,1> > -{}; - -} - -template -class GeneralProduct - : internal::no_assignment_operator, - public Matrix::ReturnType,1,1> -{ - typedef Matrix::ReturnType,1,1> Base; - public: - GeneralProduct(const Lhs& lhs, const Rhs& rhs) - { - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - - Base::coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum(); - } - - /** Convertion to scalar */ - operator const typename Base::Scalar() const { - return Base::coeff(0,0); - } -}; - -/*********************************************************************** -* Implementation of Outer Vector Vector Product -***********************************************************************/ - -namespace internal { - -// Column major -template -EIGEN_DONT_INLINE void outer_product_selector_run(const ProductType& prod, Dest& dest, const Func& func, const false_type&) -{ - typedef typename Dest::Index Index; - // FIXME make sure lhs is sequentially stored - // FIXME not very good if rhs is real and lhs complex while alpha is real too - const Index cols = dest.cols(); - for (Index j=0; j -EIGEN_DONT_INLINE void outer_product_selector_run(const ProductType& prod, Dest& dest, const Func& func, const true_type&) { - typedef typename Dest::Index Index; - // FIXME make sure rhs is sequentially stored - // FIXME not very good if lhs is real and rhs complex while alpha is real too - const Index rows = dest.rows(); - for (Index i=0; i -struct traits > - : traits, Lhs, Rhs> > -{}; - -} - -template -class GeneralProduct - : public ProductBase, Lhs, Rhs> -{ - template struct is_row_major : internal::conditional<(int(T::Flags)&RowMajorBit), internal::true_type, internal::false_type>::type {}; - - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) - - GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - { - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - } - - struct set { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() = src; } }; - struct add { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() += src; } }; - struct sub { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() -= src; } }; - struct adds { - Scalar m_scale; - adds(const Scalar& s) : m_scale(s) {} - template void operator()(const Dst& dst, const Src& src) const { - dst.const_cast_derived() += m_scale * src; - } - }; - - template - inline void evalTo(Dest& dest) const { - internal::outer_product_selector_run(*this, dest, set(), is_row_major()); - } - - template - inline void addTo(Dest& dest) const { - internal::outer_product_selector_run(*this, dest, add(), is_row_major()); - } - - template - inline void subTo(Dest& dest) const { - internal::outer_product_selector_run(*this, dest, sub(), is_row_major()); - } - - template void scaleAndAddTo(Dest& dest, const Scalar& alpha) const - { - internal::outer_product_selector_run(*this, dest, adds(alpha), is_row_major()); - } -}; - -/*********************************************************************** -* Implementation of General Matrix Vector Product -***********************************************************************/ - -/* According to the shape/flags of the matrix we have to distinghish 3 different cases: - * 1 - the matrix is col-major, BLAS compatible and M is large => call fast BLAS-like colmajor routine - * 2 - the matrix is row-major, BLAS compatible and N is large => call fast BLAS-like rowmajor routine - * 3 - all other cases are handled using a simple loop along the outer-storage direction. - * Therefore we need a lower level meta selector. - * Furthermore, if the matrix is the rhs, then the product has to be transposed. - */ -namespace internal { - -template -struct traits > - : traits, Lhs, Rhs> > -{}; - -template -struct gemv_selector; - -} // end namespace internal - -template -class GeneralProduct - : public ProductBase, Lhs, Rhs> -{ - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) - - typedef typename Lhs::Scalar LhsScalar; - typedef typename Rhs::Scalar RhsScalar; - - GeneralProduct(const Lhs& a_lhs, const Rhs& a_rhs) : Base(a_lhs,a_rhs) - { -// EIGEN_STATIC_ASSERT((internal::is_same::value), -// YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - } - - enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight }; - typedef typename internal::conditional::type MatrixType; - - template void scaleAndAddTo(Dest& dst, const Scalar& alpha) const - { - eigen_assert(m_lhs.rows() == dst.rows() && m_rhs.cols() == dst.cols()); - internal::gemv_selector::HasUsableDirectAccess)>::run(*this, dst, alpha); - } -}; - -namespace internal { - -// The vector is on the left => transposition -template -struct gemv_selector -{ - template - static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) - { - Transpose destT(dest); - enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor }; - gemv_selector - ::run(GeneralProduct,Transpose, GemvProduct> - (prod.rhs().transpose(), prod.lhs().transpose()), destT, alpha); - } -}; - -template struct gemv_static_vector_if; - -template -struct gemv_static_vector_if -{ - EIGEN_STRONG_INLINE Scalar* data() { eigen_internal_assert(false && "should never be called"); return 0; } -}; - -template -struct gemv_static_vector_if -{ - EIGEN_STRONG_INLINE Scalar* data() { return 0; } -}; - -template -struct gemv_static_vector_if -{ - #if EIGEN_ALIGN_STATICALLY - internal::plain_array m_data; - EIGEN_STRONG_INLINE Scalar* data() { return m_data.array; } - #else - // Some architectures cannot align on the stack, - // => let's manually enforce alignment by allocating more data and return the address of the first aligned element. - enum { - ForceAlignment = internal::packet_traits::Vectorizable, - PacketSize = internal::packet_traits::size - }; - internal::plain_array m_data; - EIGEN_STRONG_INLINE Scalar* data() { - return ForceAlignment - ? reinterpret_cast((reinterpret_cast(m_data.array) & ~(size_t(15))) + 16) - : m_data.array; - } - #endif -}; - -template<> struct gemv_selector -{ - template - static inline void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) - { - typedef typename ProductType::Index Index; - typedef typename ProductType::LhsScalar LhsScalar; - typedef typename ProductType::RhsScalar RhsScalar; - typedef typename ProductType::Scalar ResScalar; - typedef typename ProductType::RealScalar RealScalar; - typedef typename ProductType::ActualLhsType ActualLhsType; - typedef typename ProductType::ActualRhsType ActualRhsType; - typedef typename ProductType::LhsBlasTraits LhsBlasTraits; - typedef typename ProductType::RhsBlasTraits RhsBlasTraits; - typedef Map, Aligned> MappedDest; - - ActualLhsType actualLhs = LhsBlasTraits::extract(prod.lhs()); - ActualRhsType actualRhs = RhsBlasTraits::extract(prod.rhs()); - - ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) - * RhsBlasTraits::extractScalarFactor(prod.rhs()); - - // make sure Dest is a compile-time vector type (bug 1166) - typedef typename conditional::type ActualDest; - - enum { - // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 - // on, the other hand it is good for the cache to pack the vector anyways... - EvalToDestAtCompileTime = (ActualDest::InnerStrideAtCompileTime==1), - ComplexByReal = (NumTraits::IsComplex) && (!NumTraits::IsComplex), - MightCannotUseDest = (ActualDest::InnerStrideAtCompileTime!=1) || ComplexByReal - }; - - gemv_static_vector_if static_dest; - - bool alphaIsCompatible = (!ComplexByReal) || (numext::imag(actualAlpha)==RealScalar(0)); - bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible; - - RhsScalar compatibleAlpha = get_factor::run(actualAlpha); - - ei_declare_aligned_stack_constructed_variable(ResScalar,actualDestPtr,dest.size(), - evalToDest ? dest.data() : static_dest.data()); - - if(!evalToDest) - { - #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - int size = dest.size(); - EIGEN_DENSE_STORAGE_CTOR_PLUGIN - #endif - if(!alphaIsCompatible) - { - MappedDest(actualDestPtr, dest.size()).setZero(); - compatibleAlpha = RhsScalar(1); - } - else - MappedDest(actualDestPtr, dest.size()) = dest; - } - - general_matrix_vector_product - ::run( - actualLhs.rows(), actualLhs.cols(), - actualLhs.data(), actualLhs.outerStride(), - actualRhs.data(), actualRhs.innerStride(), - actualDestPtr, 1, - compatibleAlpha); - - if (!evalToDest) - { - if(!alphaIsCompatible) - dest += actualAlpha * MappedDest(actualDestPtr, dest.size()); - else - dest = MappedDest(actualDestPtr, dest.size()); - } - } -}; - -template<> struct gemv_selector -{ - template - static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) - { - typedef typename ProductType::LhsScalar LhsScalar; - typedef typename ProductType::RhsScalar RhsScalar; - typedef typename ProductType::Scalar ResScalar; - typedef typename ProductType::Index Index; - typedef typename ProductType::ActualLhsType ActualLhsType; - typedef typename ProductType::ActualRhsType ActualRhsType; - typedef typename ProductType::_ActualRhsType _ActualRhsType; - typedef typename ProductType::LhsBlasTraits LhsBlasTraits; - typedef typename ProductType::RhsBlasTraits RhsBlasTraits; - - typename add_const::type actualLhs = LhsBlasTraits::extract(prod.lhs()); - typename add_const::type actualRhs = RhsBlasTraits::extract(prod.rhs()); - - ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) - * RhsBlasTraits::extractScalarFactor(prod.rhs()); - - enum { - // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 - // on, the other hand it is good for the cache to pack the vector anyways... - DirectlyUseRhs = _ActualRhsType::InnerStrideAtCompileTime==1 - }; - - gemv_static_vector_if static_rhs; - - ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhsPtr,actualRhs.size(), - DirectlyUseRhs ? const_cast(actualRhs.data()) : static_rhs.data()); - - if(!DirectlyUseRhs) - { - #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - int size = actualRhs.size(); - EIGEN_DENSE_STORAGE_CTOR_PLUGIN - #endif - Map(actualRhsPtr, actualRhs.size()) = actualRhs; - } - - general_matrix_vector_product - ::run( - actualLhs.rows(), actualLhs.cols(), - actualLhs.data(), actualLhs.outerStride(), - actualRhsPtr, 1, - dest.data(), dest.col(0).innerStride(), //NOTE if dest is not a vector at compile-time, then dest.innerStride() might be wrong. (bug 1166) - actualAlpha); - } -}; - -template<> struct gemv_selector -{ - template - static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) - { - typedef typename Dest::Index Index; - // TODO makes sure dest is sequentially stored in memory, otherwise use a temp - const Index size = prod.rhs().rows(); - for(Index k=0; k struct gemv_selector -{ - template - static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) - { - typedef typename Dest::Index Index; - // TODO makes sure rhs is sequentially stored in memory, otherwise use a temp - const Index rows = prod.rows(); - for(Index i=0; i -template -inline const typename ProductReturnType::Type -MatrixBase::operator*(const MatrixBase &other) const -{ - // A note regarding the function declaration: In MSVC, this function will sometimes - // not be inlined since DenseStorage is an unwindable object for dynamic - // matrices and product types are holding a member to store the result. - // Thus it does not help tagging this function with EIGEN_STRONG_INLINE. - enum { - ProductIsValid = Derived::ColsAtCompileTime==Dynamic - || OtherDerived::RowsAtCompileTime==Dynamic - || int(Derived::ColsAtCompileTime)==int(OtherDerived::RowsAtCompileTime), - AreVectors = Derived::IsVectorAtCompileTime && OtherDerived::IsVectorAtCompileTime, - SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(Derived,OtherDerived) - }; - // note to the lost user: - // * for a dot product use: v1.dot(v2) - // * for a coeff-wise product use: v1.cwiseProduct(v2) - EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes), - INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS) - EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors), - INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) - EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) -#ifdef EIGEN_DEBUG_PRODUCT - internal::product_type::debug(); -#endif - return typename ProductReturnType::Type(derived(), other.derived()); -} - -/** \returns an expression of the matrix product of \c *this and \a other without implicit evaluation. - * - * The returned product will behave like any other expressions: the coefficients of the product will be - * computed once at a time as requested. This might be useful in some extremely rare cases when only - * a small and no coherent fraction of the result's coefficients have to be computed. - * - * \warning This version of the matrix product can be much much slower. So use it only if you know - * what you are doing and that you measured a true speed improvement. - * - * \sa operator*(const MatrixBase&) - */ -template -template -const typename LazyProductReturnType::Type -MatrixBase::lazyProduct(const MatrixBase &other) const -{ - enum { - ProductIsValid = Derived::ColsAtCompileTime==Dynamic - || OtherDerived::RowsAtCompileTime==Dynamic - || int(Derived::ColsAtCompileTime)==int(OtherDerived::RowsAtCompileTime), - AreVectors = Derived::IsVectorAtCompileTime && OtherDerived::IsVectorAtCompileTime, - SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(Derived,OtherDerived) - }; - // note to the lost user: - // * for a dot product use: v1.dot(v2) - // * for a coeff-wise product use: v1.cwiseProduct(v2) - EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes), - INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS) - EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors), - INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) - EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) - - return typename LazyProductReturnType::Type(derived(), other.derived()); -} - -} // end namespace Eigen - -#endif // EIGEN_PRODUCT_H diff --git a/splinter/src/Core/GenericPacketMath.h b/splinter/src/Core/GenericPacketMath.h deleted file mode 100644 index 5f783ebeee..0000000000 --- a/splinter/src/Core/GenericPacketMath.h +++ /dev/null @@ -1,350 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_GENERIC_PACKET_MATH_H -#define EIGEN_GENERIC_PACKET_MATH_H - -namespace Eigen { - -namespace internal { - -/** \internal - * \file GenericPacketMath.h - * - * Default implementation for types not supported by the vectorization. - * In practice these functions are provided to make easier the writing - * of generic vectorized code. - */ - -#ifndef EIGEN_DEBUG_ALIGNED_LOAD -#define EIGEN_DEBUG_ALIGNED_LOAD -#endif - -#ifndef EIGEN_DEBUG_UNALIGNED_LOAD -#define EIGEN_DEBUG_UNALIGNED_LOAD -#endif - -#ifndef EIGEN_DEBUG_ALIGNED_STORE -#define EIGEN_DEBUG_ALIGNED_STORE -#endif - -#ifndef EIGEN_DEBUG_UNALIGNED_STORE -#define EIGEN_DEBUG_UNALIGNED_STORE -#endif - -struct default_packet_traits -{ - enum { - HasAdd = 1, - HasSub = 1, - HasMul = 1, - HasNegate = 1, - HasAbs = 1, - HasAbs2 = 1, - HasMin = 1, - HasMax = 1, - HasConj = 1, - HasSetLinear = 1, - - HasDiv = 0, - HasSqrt = 0, - HasExp = 0, - HasLog = 0, - HasPow = 0, - - HasSin = 0, - HasCos = 0, - HasTan = 0, - HasASin = 0, - HasACos = 0, - HasATan = 0 - }; -}; - -template struct packet_traits : default_packet_traits -{ - typedef T type; - enum { - Vectorizable = 0, - size = 1, - AlignedOnScalar = 0 - }; - enum { - HasAdd = 0, - HasSub = 0, - HasMul = 0, - HasNegate = 0, - HasAbs = 0, - HasAbs2 = 0, - HasMin = 0, - HasMax = 0, - HasConj = 0, - HasSetLinear = 0 - }; -}; - -/** \internal \returns a + b (coeff-wise) */ -template inline Packet -padd(const Packet& a, - const Packet& b) { return a+b; } - -/** \internal \returns a - b (coeff-wise) */ -template inline Packet -psub(const Packet& a, - const Packet& b) { return a-b; } - -/** \internal \returns -a (coeff-wise) */ -template inline Packet -pnegate(const Packet& a) { return -a; } - -/** \internal \returns conj(a) (coeff-wise) */ -template inline Packet -pconj(const Packet& a) { return numext::conj(a); } - -/** \internal \returns a * b (coeff-wise) */ -template inline Packet -pmul(const Packet& a, - const Packet& b) { return a*b; } - -/** \internal \returns a / b (coeff-wise) */ -template inline Packet -pdiv(const Packet& a, - const Packet& b) { return a/b; } - -/** \internal \returns the min of \a a and \a b (coeff-wise) */ -template inline Packet -pmin(const Packet& a, - const Packet& b) { using std::min; return (min)(a, b); } - -/** \internal \returns the max of \a a and \a b (coeff-wise) */ -template inline Packet -pmax(const Packet& a, - const Packet& b) { using std::max; return (max)(a, b); } - -/** \internal \returns the absolute value of \a a */ -template inline Packet -pabs(const Packet& a) { using std::abs; return abs(a); } - -/** \internal \returns the bitwise and of \a a and \a b */ -template inline Packet -pand(const Packet& a, const Packet& b) { return a & b; } - -/** \internal \returns the bitwise or of \a a and \a b */ -template inline Packet -por(const Packet& a, const Packet& b) { return a | b; } - -/** \internal \returns the bitwise xor of \a a and \a b */ -template inline Packet -pxor(const Packet& a, const Packet& b) { return a ^ b; } - -/** \internal \returns the bitwise andnot of \a a and \a b */ -template inline Packet -pandnot(const Packet& a, const Packet& b) { return a & (!b); } - -/** \internal \returns a packet version of \a *from, from must be 16 bytes aligned */ -template inline Packet -pload(const typename unpacket_traits::type* from) { return *from; } - -/** \internal \returns a packet version of \a *from, (un-aligned load) */ -template inline Packet -ploadu(const typename unpacket_traits::type* from) { return *from; } - -/** \internal \returns a packet with elements of \a *from duplicated. - * For instance, for a packet of 8 elements, 4 scalar will be read from \a *from and - * duplicated to form: {from[0],from[0],from[1],from[1],,from[2],from[2],,from[3],from[3]} - * Currently, this function is only used for scalar * complex products. - */ -template inline Packet -ploaddup(const typename unpacket_traits::type* from) { return *from; } - -/** \internal \returns a packet with constant coefficients \a a, e.g.: (a,a,a,a) */ -template inline Packet -pset1(const typename unpacket_traits::type& a) { return a; } - -/** \internal \brief Returns a packet with coefficients (a,a+1,...,a+packet_size-1). */ -template inline typename packet_traits::type -plset(const Scalar& a) { return a; } - -/** \internal copy the packet \a from to \a *to, \a to must be 16 bytes aligned */ -template inline void pstore(Scalar* to, const Packet& from) -{ (*to) = from; } - -/** \internal copy the packet \a from to \a *to, (un-aligned store) */ -template inline void pstoreu(Scalar* to, const Packet& from) -{ (*to) = from; } - -/** \internal tries to do cache prefetching of \a addr */ -template inline void prefetch(const Scalar* addr) -{ -#if !defined(_MSC_VER) -__builtin_prefetch(addr); -#endif -} - -/** \internal \returns the first element of a packet */ -template inline typename unpacket_traits::type pfirst(const Packet& a) -{ return a; } - -/** \internal \returns a packet where the element i contains the sum of the packet of \a vec[i] */ -template inline Packet -preduxp(const Packet* vecs) { return vecs[0]; } - -/** \internal \returns the sum of the elements of \a a*/ -template inline typename unpacket_traits::type predux(const Packet& a) -{ return a; } - -/** \internal \returns the product of the elements of \a a*/ -template inline typename unpacket_traits::type predux_mul(const Packet& a) -{ return a; } - -/** \internal \returns the min of the elements of \a a*/ -template inline typename unpacket_traits::type predux_min(const Packet& a) -{ return a; } - -/** \internal \returns the max of the elements of \a a*/ -template inline typename unpacket_traits::type predux_max(const Packet& a) -{ return a; } - -/** \internal \returns the reversed elements of \a a*/ -template inline Packet preverse(const Packet& a) -{ return a; } - - -/** \internal \returns \a a with real and imaginary part flipped (for complex type only) */ -template inline Packet pcplxflip(const Packet& a) -{ - // FIXME: uncomment the following in case we drop the internal imag and real functions. -// using std::imag; -// using std::real; - return Packet(imag(a),real(a)); -} - -/************************** -* Special math functions -***************************/ - -/** \internal \returns the sine of \a a (coeff-wise) */ -template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS -Packet psin(const Packet& a) { using std::sin; return sin(a); } - -/** \internal \returns the cosine of \a a (coeff-wise) */ -template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS -Packet pcos(const Packet& a) { using std::cos; return cos(a); } - -/** \internal \returns the tan of \a a (coeff-wise) */ -template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS -Packet ptan(const Packet& a) { using std::tan; return tan(a); } - -/** \internal \returns the arc sine of \a a (coeff-wise) */ -template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS -Packet pasin(const Packet& a) { using std::asin; return asin(a); } - -/** \internal \returns the arc cosine of \a a (coeff-wise) */ -template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS -Packet pacos(const Packet& a) { using std::acos; return acos(a); } - -/** \internal \returns the exp of \a a (coeff-wise) */ -template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS -Packet pexp(const Packet& a) { using std::exp; return exp(a); } - -/** \internal \returns the log of \a a (coeff-wise) */ -template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS -Packet plog(const Packet& a) { using std::log; return log(a); } - -/** \internal \returns the square-root of \a a (coeff-wise) */ -template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS -Packet psqrt(const Packet& a) { using std::sqrt; return sqrt(a); } - -/*************************************************************************** -* The following functions might not have to be overwritten for vectorized types -***************************************************************************/ - -/** \internal copy a packet with constant coeficient \a a (e.g., [a,a,a,a]) to \a *to. \a to must be 16 bytes aligned */ -// NOTE: this function must really be templated on the packet type (think about different packet types for the same scalar type) -template -inline void pstore1(typename unpacket_traits::type* to, const typename unpacket_traits::type& a) -{ - pstore(to, pset1(a)); -} - -/** \internal \returns a * b + c (coeff-wise) */ -template inline Packet -pmadd(const Packet& a, - const Packet& b, - const Packet& c) -{ return padd(pmul(a, b),c); } - -/** \internal \returns a packet version of \a *from. - * If LoadMode equals #Aligned, \a from must be 16 bytes aligned */ -template -inline Packet ploadt(const typename unpacket_traits::type* from) -{ - if(LoadMode == Aligned) - return pload(from); - else - return ploadu(from); -} - -/** \internal copy the packet \a from to \a *to. - * If StoreMode equals #Aligned, \a to must be 16 bytes aligned */ -template -inline void pstoret(Scalar* to, const Packet& from) -{ - if(LoadMode == Aligned) - pstore(to, from); - else - pstoreu(to, from); -} - -/** \internal default implementation of palign() allowing partial specialization */ -template -struct palign_impl -{ - // by default data are aligned, so there is nothing to be done :) - static inline void run(PacketType&, const PacketType&) {} -}; - -/** \internal update \a first using the concatenation of the packet_size minus \a Offset last elements - * of \a first and \a Offset first elements of \a second. - * - * This function is currently only used to optimize matrix-vector products on unligned matrices. - * It takes 2 packets that represent a contiguous memory array, and returns a packet starting - * at the position \a Offset. For instance, for packets of 4 elements, we have: - * Input: - * - first = {f0,f1,f2,f3} - * - second = {s0,s1,s2,s3} - * Output: - * - if Offset==0 then {f0,f1,f2,f3} - * - if Offset==1 then {f1,f2,f3,s0} - * - if Offset==2 then {f2,f3,s0,s1} - * - if Offset==3 then {f3,s0,s1,s3} - */ -template -inline void palign(PacketType& first, const PacketType& second) -{ - palign_impl::run(first,second); -} - -/*************************************************************************** -* Fast complex products (GCC generates a function call which is very slow) -***************************************************************************/ - -template<> inline std::complex pmul(const std::complex& a, const std::complex& b) -{ return std::complex(real(a)*real(b) - imag(a)*imag(b), imag(a)*real(b) + real(a)*imag(b)); } - -template<> inline std::complex pmul(const std::complex& a, const std::complex& b) -{ return std::complex(real(a)*real(b) - imag(a)*imag(b), imag(a)*real(b) + real(a)*imag(b)); } - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_GENERIC_PACKET_MATH_H - diff --git a/splinter/src/Core/GlobalFunctions.h b/splinter/src/Core/GlobalFunctions.h deleted file mode 100644 index 2acf977233..0000000000 --- a/splinter/src/Core/GlobalFunctions.h +++ /dev/null @@ -1,92 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2010-2012 Gael Guennebaud -// Copyright (C) 2010 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_GLOBAL_FUNCTIONS_H -#define EIGEN_GLOBAL_FUNCTIONS_H - -#define EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(NAME,FUNCTOR) \ - template \ - inline const Eigen::CwiseUnaryOp, const Derived> \ - NAME(const Eigen::ArrayBase& x) { \ - return x.derived(); \ - } - -#define EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(NAME,FUNCTOR) \ - \ - template \ - struct NAME##_retval > \ - { \ - typedef const Eigen::CwiseUnaryOp, const Derived> type; \ - }; \ - template \ - struct NAME##_impl > \ - { \ - static inline typename NAME##_retval >::type run(const Eigen::ArrayBase& x) \ - { \ - return x.derived(); \ - } \ - }; - - -namespace Eigen -{ - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(real,scalar_real_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(imag,scalar_imag_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(conj,scalar_conjugate_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sin,scalar_sin_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cos,scalar_cos_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(asin,scalar_asin_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(acos,scalar_acos_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(tan,scalar_tan_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(exp,scalar_exp_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log,scalar_log_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(abs,scalar_abs_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sqrt,scalar_sqrt_op) - - template - inline const Eigen::CwiseUnaryOp, const Derived> - pow(const Eigen::ArrayBase& x, const typename Derived::Scalar& exponent) { - return x.derived().pow(exponent); - } - - template - inline const Eigen::CwiseBinaryOp, const Derived, const Derived> - pow(const Eigen::ArrayBase& x, const Eigen::ArrayBase& exponents) - { - return Eigen::CwiseBinaryOp, const Derived, const Derived>( - x.derived(), - exponents.derived() - ); - } - - /** - * \brief Component-wise division of a scalar by array elements. - **/ - template - inline const Eigen::CwiseUnaryOp, const Derived> - operator/(const typename Derived::Scalar& s, const Eigen::ArrayBase& a) - { - return Eigen::CwiseUnaryOp, const Derived>( - a.derived(), - Eigen::internal::scalar_inverse_mult_op(s) - ); - } - - namespace internal - { - EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(real,scalar_real_op) - EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(imag,scalar_imag_op) - EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(abs2,scalar_abs2_op) - } -} - -// TODO: cleanly disable those functions that are not supported on Array (numext::real_ref, internal::random, internal::isApprox...) - -#endif // EIGEN_GLOBAL_FUNCTIONS_H diff --git a/splinter/src/Core/IO.h b/splinter/src/Core/IO.h deleted file mode 100644 index 8d4bc59e9d..0000000000 --- a/splinter/src/Core/IO.h +++ /dev/null @@ -1,250 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2008 Benoit Jacob -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_IO_H -#define EIGEN_IO_H - -namespace Eigen { - -enum { DontAlignCols = 1 }; -enum { StreamPrecision = -1, - FullPrecision = -2 }; - -namespace internal { -template -std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& fmt); -} - -/** \class IOFormat - * \ingroup Core_Module - * - * \brief Stores a set of parameters controlling the way matrices are printed - * - * List of available parameters: - * - \b precision number of digits for floating point values, or one of the special constants \c StreamPrecision and \c FullPrecision. - * The default is the special value \c StreamPrecision which means to use the - * stream's own precision setting, as set for instance using \c cout.precision(3). The other special value - * \c FullPrecision means that the number of digits will be computed to match the full precision of each floating-point - * type. - * - \b flags an OR-ed combination of flags, the default value is 0, the only currently available flag is \c DontAlignCols which - * allows to disable the alignment of columns, resulting in faster code. - * - \b coeffSeparator string printed between two coefficients of the same row - * - \b rowSeparator string printed between two rows - * - \b rowPrefix string printed at the beginning of each row - * - \b rowSuffix string printed at the end of each row - * - \b matPrefix string printed at the beginning of the matrix - * - \b matSuffix string printed at the end of the matrix - * - * Example: \include IOFormat.cpp - * Output: \verbinclude IOFormat.out - * - * \sa DenseBase::format(), class WithFormat - */ -struct IOFormat -{ - /** Default contructor, see class IOFormat for the meaning of the parameters */ - IOFormat(int _precision = StreamPrecision, int _flags = 0, - const std::string& _coeffSeparator = " ", - const std::string& _rowSeparator = "\n", const std::string& _rowPrefix="", const std::string& _rowSuffix="", - const std::string& _matPrefix="", const std::string& _matSuffix="") - : matPrefix(_matPrefix), matSuffix(_matSuffix), rowPrefix(_rowPrefix), rowSuffix(_rowSuffix), rowSeparator(_rowSeparator), - rowSpacer(""), coeffSeparator(_coeffSeparator), precision(_precision), flags(_flags) - { - int i = int(matSuffix.length())-1; - while (i>=0 && matSuffix[i]!='\n') - { - rowSpacer += ' '; - i--; - } - } - std::string matPrefix, matSuffix; - std::string rowPrefix, rowSuffix, rowSeparator, rowSpacer; - std::string coeffSeparator; - int precision; - int flags; -}; - -/** \class WithFormat - * \ingroup Core_Module - * - * \brief Pseudo expression providing matrix output with given format - * - * \param ExpressionType the type of the object on which IO stream operations are performed - * - * This class represents an expression with stream operators controlled by a given IOFormat. - * It is the return type of DenseBase::format() - * and most of the time this is the only way it is used. - * - * See class IOFormat for some examples. - * - * \sa DenseBase::format(), class IOFormat - */ -template -class WithFormat -{ - public: - - WithFormat(const ExpressionType& matrix, const IOFormat& format) - : m_matrix(matrix), m_format(format) - {} - - friend std::ostream & operator << (std::ostream & s, const WithFormat& wf) - { - return internal::print_matrix(s, wf.m_matrix.eval(), wf.m_format); - } - - protected: - const typename ExpressionType::Nested m_matrix; - IOFormat m_format; -}; - -/** \returns a WithFormat proxy object allowing to print a matrix the with given - * format \a fmt. - * - * See class IOFormat for some examples. - * - * \sa class IOFormat, class WithFormat - */ -template -inline const WithFormat -DenseBase::format(const IOFormat& fmt) const -{ - return WithFormat(derived(), fmt); -} - -namespace internal { - -template -struct significant_decimals_default_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline int run() - { - using std::ceil; - using std::log; - return cast(ceil(-log(NumTraits::epsilon())/log(RealScalar(10)))); - } -}; - -template -struct significant_decimals_default_impl -{ - static inline int run() - { - return 0; - } -}; - -template -struct significant_decimals_impl - : significant_decimals_default_impl::IsInteger> -{}; - -/** \internal - * print the matrix \a _m to the output stream \a s using the output format \a fmt */ -template -std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& fmt) -{ - if(_m.size() == 0) - { - s << fmt.matPrefix << fmt.matSuffix; - return s; - } - - typename Derived::Nested m = _m; - typedef typename Derived::Scalar Scalar; - typedef typename Derived::Index Index; - - Index width = 0; - - std::streamsize explicit_precision; - if(fmt.precision == StreamPrecision) - { - explicit_precision = 0; - } - else if(fmt.precision == FullPrecision) - { - if (NumTraits::IsInteger) - { - explicit_precision = 0; - } - else - { - explicit_precision = significant_decimals_impl::run(); - } - } - else - { - explicit_precision = fmt.precision; - } - - std::streamsize old_precision = 0; - if(explicit_precision) old_precision = s.precision(explicit_precision); - - bool align_cols = !(fmt.flags & DontAlignCols); - if(align_cols) - { - // compute the largest width - for(Index j = 0; j < m.cols(); ++j) - for(Index i = 0; i < m.rows(); ++i) - { - std::stringstream sstr; - sstr.copyfmt(s); - sstr << m.coeff(i,j); - width = std::max(width, Index(sstr.str().length())); - } - } - s << fmt.matPrefix; - for(Index i = 0; i < m.rows(); ++i) - { - if (i) - s << fmt.rowSpacer; - s << fmt.rowPrefix; - if(width) s.width(width); - s << m.coeff(i, 0); - for(Index j = 1; j < m.cols(); ++j) - { - s << fmt.coeffSeparator; - if (width) s.width(width); - s << m.coeff(i, j); - } - s << fmt.rowSuffix; - if( i < m.rows() - 1) - s << fmt.rowSeparator; - } - s << fmt.matSuffix; - if(explicit_precision) s.precision(old_precision); - return s; -} - -} // end namespace internal - -/** \relates DenseBase - * - * Outputs the matrix, to the given stream. - * - * If you wish to print the matrix with a format different than the default, use DenseBase::format(). - * - * It is also possible to change the default format by defining EIGEN_DEFAULT_IO_FORMAT before including Eigen headers. - * If not defined, this will automatically be defined to Eigen::IOFormat(), that is the Eigen::IOFormat with default parameters. - * - * \sa DenseBase::format() - */ -template -std::ostream & operator << -(std::ostream & s, - const DenseBase & m) -{ - return internal::print_matrix(s, m.eval(), EIGEN_DEFAULT_IO_FORMAT); -} - -} // end namespace Eigen - -#endif // EIGEN_IO_H diff --git a/splinter/src/Core/Map.h b/splinter/src/Core/Map.h deleted file mode 100644 index f804c89d63..0000000000 --- a/splinter/src/Core/Map.h +++ /dev/null @@ -1,192 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2007-2010 Benoit Jacob -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_MAP_H -#define EIGEN_MAP_H - -namespace Eigen { - -/** \class Map - * \ingroup Core_Module - * - * \brief A matrix or vector expression mapping an existing array of data. - * - * \tparam PlainObjectType the equivalent matrix type of the mapped data - * \tparam MapOptions specifies whether the pointer is \c #Aligned, or \c #Unaligned. - * The default is \c #Unaligned. - * \tparam StrideType optionally specifies strides. By default, Map assumes the memory layout - * of an ordinary, contiguous array. This can be overridden by specifying strides. - * The type passed here must be a specialization of the Stride template, see examples below. - * - * This class represents a matrix or vector expression mapping an existing array of data. - * It can be used to let Eigen interface without any overhead with non-Eigen data structures, - * such as plain C arrays or structures from other libraries. By default, it assumes that the - * data is laid out contiguously in memory. You can however override this by explicitly specifying - * inner and outer strides. - * - * Here's an example of simply mapping a contiguous array as a \ref TopicStorageOrders "column-major" matrix: - * \include Map_simple.cpp - * Output: \verbinclude Map_simple.out - * - * If you need to map non-contiguous arrays, you can do so by specifying strides: - * - * Here's an example of mapping an array as a vector, specifying an inner stride, that is, the pointer - * increment between two consecutive coefficients. Here, we're specifying the inner stride as a compile-time - * fixed value. - * \include Map_inner_stride.cpp - * Output: \verbinclude Map_inner_stride.out - * - * Here's an example of mapping an array while specifying an outer stride. Here, since we're mapping - * as a column-major matrix, 'outer stride' means the pointer increment between two consecutive columns. - * Here, we're specifying the outer stride as a runtime parameter. Note that here \c OuterStride<> is - * a short version of \c OuterStride because the default template parameter of OuterStride - * is \c Dynamic - * \include Map_outer_stride.cpp - * Output: \verbinclude Map_outer_stride.out - * - * For more details and for an example of specifying both an inner and an outer stride, see class Stride. - * - * \b Tip: to change the array of data mapped by a Map object, you can use the C++ - * placement new syntax: - * - * Example: \include Map_placement_new.cpp - * Output: \verbinclude Map_placement_new.out - * - * This class is the return type of PlainObjectBase::Map() but can also be used directly. - * - * \sa PlainObjectBase::Map(), \ref TopicStorageOrders - */ - -namespace internal { -template -struct traits > - : public traits -{ - typedef traits TraitsBase; - typedef typename PlainObjectType::Index Index; - typedef typename PlainObjectType::Scalar Scalar; - enum { - InnerStrideAtCompileTime = StrideType::InnerStrideAtCompileTime == 0 - ? int(PlainObjectType::InnerStrideAtCompileTime) - : int(StrideType::InnerStrideAtCompileTime), - OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0 - ? int(PlainObjectType::OuterStrideAtCompileTime) - : int(StrideType::OuterStrideAtCompileTime), - HasNoInnerStride = InnerStrideAtCompileTime == 1, - HasNoOuterStride = StrideType::OuterStrideAtCompileTime == 0, - HasNoStride = HasNoInnerStride && HasNoOuterStride, - IsAligned = bool(EIGEN_ALIGN) && ((int(MapOptions)&Aligned)==Aligned), - IsDynamicSize = PlainObjectType::SizeAtCompileTime==Dynamic, - KeepsPacketAccess = bool(HasNoInnerStride) - && ( bool(IsDynamicSize) - || HasNoOuterStride - || ( OuterStrideAtCompileTime!=Dynamic - && ((static_cast(sizeof(Scalar))*OuterStrideAtCompileTime)%16)==0 ) ), - Flags0 = TraitsBase::Flags & (~NestByRefBit), - Flags1 = IsAligned ? (int(Flags0) | AlignedBit) : (int(Flags0) & ~AlignedBit), - Flags2 = (bool(HasNoStride) || bool(PlainObjectType::IsVectorAtCompileTime)) - ? int(Flags1) : int(Flags1 & ~LinearAccessBit), - Flags3 = is_lvalue::value ? int(Flags2) : (int(Flags2) & ~LvalueBit), - Flags = KeepsPacketAccess ? int(Flags3) : (int(Flags3) & ~PacketAccessBit) - }; -private: - enum { Options }; // Expressions don't have Options -}; -} - -template class Map - : public MapBase > -{ - public: - - typedef MapBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(Map) - - typedef typename Base::PointerType PointerType; -#if EIGEN2_SUPPORT_STAGE <= STAGE30_FULL_EIGEN3_API - typedef const Scalar* PointerArgType; - inline PointerType cast_to_pointer_type(PointerArgType ptr) { return const_cast(ptr); } -#else - typedef PointerType PointerArgType; - inline PointerType cast_to_pointer_type(PointerArgType ptr) { return ptr; } -#endif - - inline Index innerStride() const - { - return StrideType::InnerStrideAtCompileTime != 0 ? m_stride.inner() : 1; - } - - inline Index outerStride() const - { - return StrideType::OuterStrideAtCompileTime != 0 ? m_stride.outer() - : IsVectorAtCompileTime ? this->size() - : int(Flags)&RowMajorBit ? this->cols() - : this->rows(); - } - - /** Constructor in the fixed-size case. - * - * \param dataPtr pointer to the array to map - * \param a_stride optional Stride object, passing the strides. - */ - inline Map(PointerArgType dataPtr, const StrideType& a_stride = StrideType()) - : Base(cast_to_pointer_type(dataPtr)), m_stride(a_stride) - { - PlainObjectType::Base::_check_template_params(); - } - - /** Constructor in the dynamic-size vector case. - * - * \param dataPtr pointer to the array to map - * \param a_size the size of the vector expression - * \param a_stride optional Stride object, passing the strides. - */ - inline Map(PointerArgType dataPtr, Index a_size, const StrideType& a_stride = StrideType()) - : Base(cast_to_pointer_type(dataPtr), a_size), m_stride(a_stride) - { - PlainObjectType::Base::_check_template_params(); - } - - /** Constructor in the dynamic-size matrix case. - * - * \param dataPtr pointer to the array to map - * \param nbRows the number of rows of the matrix expression - * \param nbCols the number of columns of the matrix expression - * \param a_stride optional Stride object, passing the strides. - */ - inline Map(PointerArgType dataPtr, Index nbRows, Index nbCols, const StrideType& a_stride = StrideType()) - : Base(cast_to_pointer_type(dataPtr), nbRows, nbCols), m_stride(a_stride) - { - PlainObjectType::Base::_check_template_params(); - } - - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Map) - - protected: - StrideType m_stride; -}; - -template -inline Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> - ::Array(const Scalar *data) -{ - this->_set_noalias(Eigen::Map(data)); -} - -template -inline Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> - ::Matrix(const Scalar *data) -{ - this->_set_noalias(Eigen::Map(data)); -} - -} // end namespace Eigen - -#endif // EIGEN_MAP_H diff --git a/splinter/src/Core/MapBase.h b/splinter/src/Core/MapBase.h deleted file mode 100644 index 81efc4a6d5..0000000000 --- a/splinter/src/Core/MapBase.h +++ /dev/null @@ -1,251 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2007-2010 Benoit Jacob -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_MAPBASE_H -#define EIGEN_MAPBASE_H - -#define EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) \ - EIGEN_STATIC_ASSERT((int(internal::traits::Flags) & LinearAccessBit) || Derived::IsVectorAtCompileTime, \ - YOU_ARE_TRYING_TO_USE_AN_INDEX_BASED_ACCESSOR_ON_AN_EXPRESSION_THAT_DOES_NOT_SUPPORT_THAT) - -namespace Eigen { - -/** \class MapBase - * \ingroup Core_Module - * - * \brief Base class for Map and Block expression with direct access - * - * \sa class Map, class Block - */ -template class MapBase - : public internal::dense_xpr_base::type -{ - public: - - typedef typename internal::dense_xpr_base::type Base; - enum { - RowsAtCompileTime = internal::traits::RowsAtCompileTime, - ColsAtCompileTime = internal::traits::ColsAtCompileTime, - SizeAtCompileTime = Base::SizeAtCompileTime - }; - - typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; - typedef typename internal::traits::Scalar Scalar; - typedef typename internal::packet_traits::type PacketScalar; - typedef typename NumTraits::Real RealScalar; - typedef typename internal::conditional< - bool(internal::is_lvalue::value), - Scalar *, - const Scalar *>::type - PointerType; - - using Base::derived; -// using Base::RowsAtCompileTime; -// using Base::ColsAtCompileTime; -// using Base::SizeAtCompileTime; - using Base::MaxRowsAtCompileTime; - using Base::MaxColsAtCompileTime; - using Base::MaxSizeAtCompileTime; - using Base::IsVectorAtCompileTime; - using Base::Flags; - using Base::IsRowMajor; - - using Base::rows; - using Base::cols; - using Base::size; - using Base::coeff; - using Base::coeffRef; - using Base::lazyAssign; - using Base::eval; - - using Base::innerStride; - using Base::outerStride; - using Base::rowStride; - using Base::colStride; - - // bug 217 - compile error on ICC 11.1 - using Base::operator=; - - typedef typename Base::CoeffReturnType CoeffReturnType; - - inline Index rows() const { return m_rows.value(); } - inline Index cols() const { return m_cols.value(); } - - /** Returns a pointer to the first coefficient of the matrix or vector. - * - * \note When addressing this data, make sure to honor the strides returned by innerStride() and outerStride(). - * - * \sa innerStride(), outerStride() - */ - inline const Scalar* data() const { return m_data; } - - inline const Scalar& coeff(Index rowId, Index colId) const - { - return m_data[colId * colStride() + rowId * rowStride()]; - } - - inline const Scalar& coeff(Index index) const - { - EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) - return m_data[index * innerStride()]; - } - - inline const Scalar& coeffRef(Index rowId, Index colId) const - { - return this->m_data[colId * colStride() + rowId * rowStride()]; - } - - inline const Scalar& coeffRef(Index index) const - { - EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) - return this->m_data[index * innerStride()]; - } - - template - inline PacketScalar packet(Index rowId, Index colId) const - { - return internal::ploadt - (m_data + (colId * colStride() + rowId * rowStride())); - } - - template - inline PacketScalar packet(Index index) const - { - EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) - return internal::ploadt(m_data + index * innerStride()); - } - - explicit inline MapBase(PointerType dataPtr) : m_data(dataPtr), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime) - { - EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) - checkSanity(); - } - - inline MapBase(PointerType dataPtr, Index vecSize) - : m_data(dataPtr), - m_rows(RowsAtCompileTime == Dynamic ? vecSize : Index(RowsAtCompileTime)), - m_cols(ColsAtCompileTime == Dynamic ? vecSize : Index(ColsAtCompileTime)) - { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - eigen_assert(vecSize >= 0); - eigen_assert(dataPtr == 0 || SizeAtCompileTime == Dynamic || SizeAtCompileTime == vecSize); - checkSanity(); - } - - inline MapBase(PointerType dataPtr, Index nbRows, Index nbCols) - : m_data(dataPtr), m_rows(nbRows), m_cols(nbCols) - { - eigen_assert( (dataPtr == 0) - || ( nbRows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == nbRows) - && nbCols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == nbCols))); - checkSanity(); - } - - #ifdef EIGEN_MAPBASE_PLUGIN - #include EIGEN_MAPBASE_PLUGIN - #endif - - protected: - - void checkSanity() const - { - EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(internal::traits::Flags&PacketAccessBit, - internal::inner_stride_at_compile_time::ret==1), - PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1); - eigen_assert(EIGEN_IMPLIES(internal::traits::Flags&AlignedBit, (size_t(m_data) % 16) == 0) - && "input pointer is not aligned on a 16 byte boundary"); - } - - PointerType m_data; - const internal::variable_if_dynamic m_rows; - const internal::variable_if_dynamic m_cols; -}; - -template class MapBase - : public MapBase -{ - typedef MapBase ReadOnlyMapBase; - public: - - typedef MapBase Base; - - typedef typename Base::Scalar Scalar; - typedef typename Base::PacketScalar PacketScalar; - typedef typename Base::Index Index; - typedef typename Base::PointerType PointerType; - - using Base::derived; - using Base::rows; - using Base::cols; - using Base::size; - using Base::coeff; - using Base::coeffRef; - - using Base::innerStride; - using Base::outerStride; - using Base::rowStride; - using Base::colStride; - - typedef typename internal::conditional< - internal::is_lvalue::value, - Scalar, - const Scalar - >::type ScalarWithConstIfNotLvalue; - - inline const Scalar* data() const { return this->m_data; } - inline ScalarWithConstIfNotLvalue* data() { return this->m_data; } // no const-cast here so non-const-correct code will give a compile error - - inline ScalarWithConstIfNotLvalue& coeffRef(Index row, Index col) - { - return this->m_data[col * colStride() + row * rowStride()]; - } - - inline ScalarWithConstIfNotLvalue& coeffRef(Index index) - { - EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) - return this->m_data[index * innerStride()]; - } - - template - inline void writePacket(Index row, Index col, const PacketScalar& val) - { - internal::pstoret - (this->m_data + (col * colStride() + row * rowStride()), val); - } - - template - inline void writePacket(Index index, const PacketScalar& val) - { - EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) - internal::pstoret - (this->m_data + index * innerStride(), val); - } - - explicit inline MapBase(PointerType dataPtr) : Base(dataPtr) {} - inline MapBase(PointerType dataPtr, Index vecSize) : Base(dataPtr, vecSize) {} - inline MapBase(PointerType dataPtr, Index nbRows, Index nbCols) : Base(dataPtr, nbRows, nbCols) {} - - Derived& operator=(const MapBase& other) - { - ReadOnlyMapBase::Base::operator=(other); - return derived(); - } - - // In theory we could simply refer to Base:Base::operator=, but MSVC does not like Base::Base, - // see bugs 821 and 920. - using ReadOnlyMapBase::Base::operator=; -}; - -#undef EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS - -} // end namespace Eigen - -#endif // EIGEN_MAPBASE_H diff --git a/splinter/src/Core/MathFunctions.h b/splinter/src/Core/MathFunctions.h deleted file mode 100644 index 4e17ecd4b4..0000000000 --- a/splinter/src/Core/MathFunctions.h +++ /dev/null @@ -1,768 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2010 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_MATHFUNCTIONS_H -#define EIGEN_MATHFUNCTIONS_H - -namespace Eigen { - -namespace internal { - -/** \internal \struct global_math_functions_filtering_base - * - * What it does: - * Defines a typedef 'type' as follows: - * - if type T has a member typedef Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl, then - * global_math_functions_filtering_base::type is a typedef for it. - * - otherwise, global_math_functions_filtering_base::type is a typedef for T. - * - * How it's used: - * To allow to defined the global math functions (like sin...) in certain cases, like the Array expressions. - * When you do sin(array1+array2), the object array1+array2 has a complicated expression type, all what you want to know - * is that it inherits ArrayBase. So we implement a partial specialization of sin_impl for ArrayBase. - * So we must make sure to use sin_impl > and not sin_impl, otherwise our partial specialization - * won't be used. How does sin know that? That's exactly what global_math_functions_filtering_base tells it. - * - * How it's implemented: - * SFINAE in the style of enable_if. Highly susceptible of breaking compilers. With GCC, it sure does work, but if you replace - * the typename dummy by an integer template parameter, it doesn't work anymore! - */ - -template -struct global_math_functions_filtering_base -{ - typedef T type; -}; - -template struct always_void { typedef void type; }; - -template -struct global_math_functions_filtering_base - ::type - > -{ - typedef typename T::Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl type; -}; - -#define EIGEN_MATHFUNC_IMPL(func, scalar) Eigen::internal::func##_impl::type> -#define EIGEN_MATHFUNC_RETVAL(func, scalar) typename Eigen::internal::func##_retval::type>::type - -/**************************************************************************** -* Implementation of real * -****************************************************************************/ - -template::IsComplex> -struct real_default_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline RealScalar run(const Scalar& x) - { - return x; - } -}; - -template -struct real_default_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline RealScalar run(const Scalar& x) - { - using std::real; - return real(x); - } -}; - -template struct real_impl : real_default_impl {}; - -template -struct real_retval -{ - typedef typename NumTraits::Real type; -}; - - -/**************************************************************************** -* Implementation of imag * -****************************************************************************/ - -template::IsComplex> -struct imag_default_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline RealScalar run(const Scalar&) - { - return RealScalar(0); - } -}; - -template -struct imag_default_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline RealScalar run(const Scalar& x) - { - using std::imag; - return imag(x); - } -}; - -template struct imag_impl : imag_default_impl {}; - -template -struct imag_retval -{ - typedef typename NumTraits::Real type; -}; - -/**************************************************************************** -* Implementation of real_ref * -****************************************************************************/ - -template -struct real_ref_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline RealScalar& run(Scalar& x) - { - return reinterpret_cast(&x)[0]; - } - static inline const RealScalar& run(const Scalar& x) - { - return reinterpret_cast(&x)[0]; - } -}; - -template -struct real_ref_retval -{ - typedef typename NumTraits::Real & type; -}; - -/**************************************************************************** -* Implementation of imag_ref * -****************************************************************************/ - -template -struct imag_ref_default_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline RealScalar& run(Scalar& x) - { - return reinterpret_cast(&x)[1]; - } - static inline const RealScalar& run(const Scalar& x) - { - return reinterpret_cast(&x)[1]; - } -}; - -template -struct imag_ref_default_impl -{ - static inline Scalar run(Scalar&) - { - return Scalar(0); - } - static inline const Scalar run(const Scalar&) - { - return Scalar(0); - } -}; - -template -struct imag_ref_impl : imag_ref_default_impl::IsComplex> {}; - -template -struct imag_ref_retval -{ - typedef typename NumTraits::Real & type; -}; - -/**************************************************************************** -* Implementation of conj * -****************************************************************************/ - -template::IsComplex> -struct conj_impl -{ - static inline Scalar run(const Scalar& x) - { - return x; - } -}; - -template -struct conj_impl -{ - static inline Scalar run(const Scalar& x) - { - using std::conj; - return conj(x); - } -}; - -template -struct conj_retval -{ - typedef Scalar type; -}; - -/**************************************************************************** -* Implementation of abs2 * -****************************************************************************/ - -template -struct abs2_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline RealScalar run(const Scalar& x) - { - return x*x; - } -}; - -template -struct abs2_impl > -{ - static inline RealScalar run(const std::complex& x) - { - return real(x)*real(x) + imag(x)*imag(x); - } -}; - -template -struct abs2_retval -{ - typedef typename NumTraits::Real type; -}; - -/**************************************************************************** -* Implementation of norm1 * -****************************************************************************/ - -template -struct norm1_default_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline RealScalar run(const Scalar& x) - { - using std::abs; - return abs(real(x)) + abs(imag(x)); - } -}; - -template -struct norm1_default_impl -{ - static inline Scalar run(const Scalar& x) - { - using std::abs; - return abs(x); - } -}; - -template -struct norm1_impl : norm1_default_impl::IsComplex> {}; - -template -struct norm1_retval -{ - typedef typename NumTraits::Real type; -}; - -/**************************************************************************** -* Implementation of hypot * -****************************************************************************/ - -template -struct hypot_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline RealScalar run(const Scalar& x, const Scalar& y) - { - using std::max; - using std::min; - using std::abs; - using std::sqrt; - RealScalar _x = abs(x); - RealScalar _y = abs(y); - RealScalar p = (max)(_x, _y); - if(p==RealScalar(0)) return RealScalar(0); - RealScalar q = (min)(_x, _y); - RealScalar qp = q/p; - return p * sqrt(RealScalar(1) + qp*qp); - } -}; - -template -struct hypot_retval -{ - typedef typename NumTraits::Real type; -}; - -/**************************************************************************** -* Implementation of cast * -****************************************************************************/ - -template -struct cast_impl -{ - static inline NewType run(const OldType& x) - { - return static_cast(x); - } -}; - -// here, for once, we're plainly returning NewType: we don't want cast to do weird things. - -template -inline NewType cast(const OldType& x) -{ - return cast_impl::run(x); -} - -/**************************************************************************** -* Implementation of atanh2 * -****************************************************************************/ - -template -struct atanh2_default_impl -{ - typedef Scalar retval; - typedef typename NumTraits::Real RealScalar; - static inline Scalar run(const Scalar& x, const Scalar& y) - { - using std::abs; - using std::log; - using std::sqrt; - Scalar z = x / y; - if (y == Scalar(0) || abs(z) > sqrt(NumTraits::epsilon())) - return RealScalar(0.5) * log((y + x) / (y - x)); - else - return z + z*z*z / RealScalar(3); - } -}; - -template -struct atanh2_default_impl -{ - static inline Scalar run(const Scalar&, const Scalar&) - { - EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) - return Scalar(0); - } -}; - -template -struct atanh2_impl : atanh2_default_impl::IsInteger> {}; - -template -struct atanh2_retval -{ - typedef Scalar type; -}; - -/**************************************************************************** -* Implementation of pow * -****************************************************************************/ - -template -struct pow_default_impl -{ - typedef Scalar retval; - static inline Scalar run(const Scalar& x, const Scalar& y) - { - using std::pow; - return pow(x, y); - } -}; - -template -struct pow_default_impl -{ - static inline Scalar run(Scalar x, Scalar y) - { - Scalar res(1); - eigen_assert(!NumTraits::IsSigned || y >= 0); - if(y & 1) res *= x; - y >>= 1; - while(y) - { - x *= x; - if(y&1) res *= x; - y >>= 1; - } - return res; - } -}; - -template -struct pow_impl : pow_default_impl::IsInteger> {}; - -template -struct pow_retval -{ - typedef Scalar type; -}; - -/**************************************************************************** -* Implementation of random * -****************************************************************************/ - -template -struct random_default_impl {}; - -template -struct random_impl : random_default_impl::IsComplex, NumTraits::IsInteger> {}; - -template -struct random_retval -{ - typedef Scalar type; -}; - -template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(const Scalar& x, const Scalar& y); -template inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(); - -template -struct random_default_impl -{ - static inline Scalar run(const Scalar& x, const Scalar& y) - { - return x + (y-x) * Scalar(std::rand()) / Scalar(RAND_MAX); - } - static inline Scalar run() - { - return run(Scalar(NumTraits::IsSigned ? -1 : 0), Scalar(1)); - } -}; - -enum { - floor_log2_terminate, - floor_log2_move_up, - floor_log2_move_down, - floor_log2_bogus -}; - -template struct floor_log2_selector -{ - enum { middle = (lower + upper) / 2, - value = (upper <= lower + 1) ? int(floor_log2_terminate) - : (n < (1 << middle)) ? int(floor_log2_move_down) - : (n==0) ? int(floor_log2_bogus) - : int(floor_log2_move_up) - }; -}; - -template::value> -struct floor_log2 {}; - -template -struct floor_log2 -{ - enum { value = floor_log2::middle>::value }; -}; - -template -struct floor_log2 -{ - enum { value = floor_log2::middle, upper>::value }; -}; - -template -struct floor_log2 -{ - enum { value = (n >= ((unsigned int)(1) << (lower+1))) ? lower+1 : lower }; -}; - -template -struct floor_log2 -{ - // no value, error at compile time -}; - -template -struct random_default_impl -{ - typedef typename NumTraits::NonInteger NonInteger; - - static inline Scalar run(const Scalar& x, const Scalar& y) - { - return x + Scalar((NonInteger(y)-x+1) * std::rand() / (RAND_MAX + NonInteger(1))); - } - - static inline Scalar run() - { -#ifdef EIGEN_MAKING_DOCS - return run(Scalar(NumTraits::IsSigned ? -10 : 0), Scalar(10)); -#else - enum { rand_bits = floor_log2<(unsigned int)(RAND_MAX)+1>::value, - scalar_bits = sizeof(Scalar) * CHAR_BIT, - shift = EIGEN_PLAIN_ENUM_MAX(0, int(rand_bits) - int(scalar_bits)), - offset = NumTraits::IsSigned ? (1 << (EIGEN_PLAIN_ENUM_MIN(rand_bits,scalar_bits)-1)) : 0 - }; - return Scalar((std::rand() >> shift) - offset); -#endif - } -}; - -template -struct random_default_impl -{ - static inline Scalar run(const Scalar& x, const Scalar& y) - { - return Scalar(random(real(x), real(y)), - random(imag(x), imag(y))); - } - static inline Scalar run() - { - typedef typename NumTraits::Real RealScalar; - return Scalar(random(), random()); - } -}; - -template -inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(const Scalar& x, const Scalar& y) -{ - return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(x, y); -} - -template -inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random() -{ - return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(); -} - -} // end namespace internal - -/**************************************************************************** -* Generic math function * -****************************************************************************/ - -namespace numext { - -template -inline EIGEN_MATHFUNC_RETVAL(real, Scalar) real(const Scalar& x) -{ - return EIGEN_MATHFUNC_IMPL(real, Scalar)::run(x); -} - -template -inline typename internal::add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) >::type real_ref(const Scalar& x) -{ - return internal::real_ref_impl::run(x); -} - -template -inline EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) real_ref(Scalar& x) -{ - return EIGEN_MATHFUNC_IMPL(real_ref, Scalar)::run(x); -} - -template -inline EIGEN_MATHFUNC_RETVAL(imag, Scalar) imag(const Scalar& x) -{ - return EIGEN_MATHFUNC_IMPL(imag, Scalar)::run(x); -} - -template -inline typename internal::add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) >::type imag_ref(const Scalar& x) -{ - return internal::imag_ref_impl::run(x); -} - -template -inline EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) imag_ref(Scalar& x) -{ - return EIGEN_MATHFUNC_IMPL(imag_ref, Scalar)::run(x); -} - -template -inline EIGEN_MATHFUNC_RETVAL(conj, Scalar) conj(const Scalar& x) -{ - return EIGEN_MATHFUNC_IMPL(conj, Scalar)::run(x); -} - -template -inline EIGEN_MATHFUNC_RETVAL(abs2, Scalar) abs2(const Scalar& x) -{ - return EIGEN_MATHFUNC_IMPL(abs2, Scalar)::run(x); -} - -template -inline EIGEN_MATHFUNC_RETVAL(norm1, Scalar) norm1(const Scalar& x) -{ - return EIGEN_MATHFUNC_IMPL(norm1, Scalar)::run(x); -} - -template -inline EIGEN_MATHFUNC_RETVAL(hypot, Scalar) hypot(const Scalar& x, const Scalar& y) -{ - return EIGEN_MATHFUNC_IMPL(hypot, Scalar)::run(x, y); -} - -template -inline EIGEN_MATHFUNC_RETVAL(atanh2, Scalar) atanh2(const Scalar& x, const Scalar& y) -{ - return EIGEN_MATHFUNC_IMPL(atanh2, Scalar)::run(x, y); -} - -template -inline EIGEN_MATHFUNC_RETVAL(pow, Scalar) pow(const Scalar& x, const Scalar& y) -{ - return EIGEN_MATHFUNC_IMPL(pow, Scalar)::run(x, y); -} - -// std::isfinite is non standard, so let's define our own version, -// even though it is not very efficient. -template bool (isfinite)(const T& x) -{ - return x::highest() && x>NumTraits::lowest(); -} - -} // end namespace numext - -namespace internal { - -/**************************************************************************** -* Implementation of fuzzy comparisons * -****************************************************************************/ - -template -struct scalar_fuzzy_default_impl {}; - -template -struct scalar_fuzzy_default_impl -{ - typedef typename NumTraits::Real RealScalar; - template - static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) - { - using std::abs; - return abs(x) <= abs(y) * prec; - } - static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) - { - using std::min; - using std::abs; - return abs(x - y) <= (min)(abs(x), abs(y)) * prec; - } - static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar& prec) - { - return x <= y || isApprox(x, y, prec); - } -}; - -template -struct scalar_fuzzy_default_impl -{ - typedef typename NumTraits::Real RealScalar; - template - static inline bool isMuchSmallerThan(const Scalar& x, const Scalar&, const RealScalar&) - { - return x == Scalar(0); - } - static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar&) - { - return x == y; - } - static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar&) - { - return x <= y; - } -}; - -template -struct scalar_fuzzy_default_impl -{ - typedef typename NumTraits::Real RealScalar; - template - static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) - { - return numext::abs2(x) <= numext::abs2(y) * prec * prec; - } - static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) - { - using std::min; - return numext::abs2(x - y) <= (min)(numext::abs2(x), numext::abs2(y)) * prec * prec; - } -}; - -template -struct scalar_fuzzy_impl : scalar_fuzzy_default_impl::IsComplex, NumTraits::IsInteger> {}; - -template -inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, - const typename NumTraits::Real &precision = NumTraits::dummy_precision()) -{ - return scalar_fuzzy_impl::template isMuchSmallerThan(x, y, precision); -} - -template -inline bool isApprox(const Scalar& x, const Scalar& y, - const typename NumTraits::Real &precision = NumTraits::dummy_precision()) -{ - return scalar_fuzzy_impl::isApprox(x, y, precision); -} - -template -inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, - const typename NumTraits::Real &precision = NumTraits::dummy_precision()) -{ - return scalar_fuzzy_impl::isApproxOrLessThan(x, y, precision); -} - -/****************************************** -*** The special case of the bool type *** -******************************************/ - -template<> struct random_impl -{ - static inline bool run() - { - return random(0,1)==0 ? false : true; - } -}; - -template<> struct scalar_fuzzy_impl -{ - typedef bool RealScalar; - - template - static inline bool isMuchSmallerThan(const bool& x, const bool&, const bool&) - { - return !x; - } - - static inline bool isApprox(bool x, bool y, bool) - { - return x == y; - } - - static inline bool isApproxOrLessThan(const bool& x, const bool& y, const bool&) - { - return (!x) || y; - } - -}; - - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_MATHFUNCTIONS_H diff --git a/splinter/src/Core/Matrix.h b/splinter/src/Core/Matrix.h deleted file mode 100644 index 02be142d8c..0000000000 --- a/splinter/src/Core/Matrix.h +++ /dev/null @@ -1,420 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2010 Benoit Jacob -// Copyright (C) 2008-2009 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_MATRIX_H -#define EIGEN_MATRIX_H - -namespace Eigen { - -/** \class Matrix - * \ingroup Core_Module - * - * \brief The matrix class, also used for vectors and row-vectors - * - * The %Matrix class is the work-horse for all \em dense (\ref dense "note") matrices and vectors within Eigen. - * Vectors are matrices with one column, and row-vectors are matrices with one row. - * - * The %Matrix class encompasses \em both fixed-size and dynamic-size objects (\ref fixedsize "note"). - * - * The first three template parameters are required: - * \tparam _Scalar \anchor matrix_tparam_scalar Numeric type, e.g. float, double, int or std::complex. - * User defined sclar types are supported as well (see \ref user_defined_scalars "here"). - * \tparam _Rows Number of rows, or \b Dynamic - * \tparam _Cols Number of columns, or \b Dynamic - * - * The remaining template parameters are optional -- in most cases you don't have to worry about them. - * \tparam _Options \anchor matrix_tparam_options A combination of either \b #RowMajor or \b #ColMajor, and of either - * \b #AutoAlign or \b #DontAlign. - * The former controls \ref TopicStorageOrders "storage order", and defaults to column-major. The latter controls alignment, which is required - * for vectorization. It defaults to aligning matrices except for fixed sizes that aren't a multiple of the packet size. - * \tparam _MaxRows Maximum number of rows. Defaults to \a _Rows (\ref maxrows "note"). - * \tparam _MaxCols Maximum number of columns. Defaults to \a _Cols (\ref maxrows "note"). - * - * Eigen provides a number of typedefs covering the usual cases. Here are some examples: - * - * \li \c Matrix2d is a 2x2 square matrix of doubles (\c Matrix) - * \li \c Vector4f is a vector of 4 floats (\c Matrix) - * \li \c RowVector3i is a row-vector of 3 ints (\c Matrix) - * - * \li \c MatrixXf is a dynamic-size matrix of floats (\c Matrix) - * \li \c VectorXf is a dynamic-size vector of floats (\c Matrix) - * - * \li \c Matrix2Xf is a partially fixed-size (dynamic-size) matrix of floats (\c Matrix) - * \li \c MatrixX3d is a partially dynamic-size (fixed-size) matrix of double (\c Matrix) - * - * See \link matrixtypedefs this page \endlink for a complete list of predefined \em %Matrix and \em Vector typedefs. - * - * You can access elements of vectors and matrices using normal subscripting: - * - * \code - * Eigen::VectorXd v(10); - * v[0] = 0.1; - * v[1] = 0.2; - * v(0) = 0.3; - * v(1) = 0.4; - * - * Eigen::MatrixXi m(10, 10); - * m(0, 1) = 1; - * m(0, 2) = 2; - * m(0, 3) = 3; - * \endcode - * - * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_MATRIX_PLUGIN. - * - * Some notes: - * - *
- *
\anchor dense Dense versus sparse:
- *
This %Matrix class handles dense, not sparse matrices and vectors. For sparse matrices and vectors, see the Sparse module. - * - * Dense matrices and vectors are plain usual arrays of coefficients. All the coefficients are stored, in an ordinary contiguous array. - * This is unlike Sparse matrices and vectors where the coefficients are stored as a list of nonzero coefficients.
- * - *
\anchor fixedsize Fixed-size versus dynamic-size:
- *
Fixed-size means that the numbers of rows and columns are known are compile-time. In this case, Eigen allocates the array - * of coefficients as a fixed-size array, as a class member. This makes sense for very small matrices, typically up to 4x4, sometimes up - * to 16x16. Larger matrices should be declared as dynamic-size even if one happens to know their size at compile-time. - * - * Dynamic-size means that the numbers of rows or columns are not necessarily known at compile-time. In this case they are runtime - * variables, and the array of coefficients is allocated dynamically on the heap. - * - * Note that \em dense matrices, be they Fixed-size or Dynamic-size, do not expand dynamically in the sense of a std::map. - * If you want this behavior, see the Sparse module.
- * - *
\anchor maxrows _MaxRows and _MaxCols:
- *
In most cases, one just leaves these parameters to the default values. - * These parameters mean the maximum size of rows and columns that the matrix may have. They are useful in cases - * when the exact numbers of rows and columns are not known are compile-time, but it is known at compile-time that they cannot - * exceed a certain value. This happens when taking dynamic-size blocks inside fixed-size matrices: in this case _MaxRows and _MaxCols - * are the dimensions of the original matrix, while _Rows and _Cols are Dynamic.
- *
- * - * \see MatrixBase for the majority of the API methods for matrices, \ref TopicClassHierarchy, - * \ref TopicStorageOrders - */ - -namespace internal { -template -struct traits > -{ - typedef _Scalar Scalar; - typedef Dense StorageKind; - typedef DenseIndex Index; - typedef MatrixXpr XprKind; - enum { - RowsAtCompileTime = _Rows, - ColsAtCompileTime = _Cols, - MaxRowsAtCompileTime = _MaxRows, - MaxColsAtCompileTime = _MaxCols, - Flags = compute_matrix_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::ret, - CoeffReadCost = NumTraits::ReadCost, - Options = _Options, - InnerStrideAtCompileTime = 1, - OuterStrideAtCompileTime = (Options&RowMajor) ? ColsAtCompileTime : RowsAtCompileTime - }; -}; -} - -template -class Matrix - : public PlainObjectBase > -{ - public: - - /** \brief Base class typedef. - * \sa PlainObjectBase - */ - typedef PlainObjectBase Base; - - enum { Options = _Options }; - - EIGEN_DENSE_PUBLIC_INTERFACE(Matrix) - - typedef typename Base::PlainObject PlainObject; - - using Base::base; - using Base::coeffRef; - - /** - * \brief Assigns matrices to each other. - * - * \note This is a special case of the templated operator=. Its purpose is - * to prevent a default operator= from hiding the templated operator=. - * - * \callgraph - */ - EIGEN_STRONG_INLINE Matrix& operator=(const Matrix& other) - { - return Base::_set(other); - } - - /** \internal - * \brief Copies the value of the expression \a other into \c *this with automatic resizing. - * - * *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized), - * it will be initialized. - * - * Note that copying a row-vector into a vector (and conversely) is allowed. - * The resizing, if any, is then done in the appropriate way so that row-vectors - * remain row-vectors and vectors remain vectors. - */ - template - EIGEN_STRONG_INLINE Matrix& operator=(const MatrixBase& other) - { - return Base::_set(other); - } - - /* Here, doxygen failed to copy the brief information when using \copydoc */ - - /** - * \brief Copies the generic expression \a other into *this. - * \copydetails DenseBase::operator=(const EigenBase &other) - */ - template - EIGEN_STRONG_INLINE Matrix& operator=(const EigenBase &other) - { - return Base::operator=(other); - } - - template - EIGEN_STRONG_INLINE Matrix& operator=(const ReturnByValue& func) - { - return Base::operator=(func); - } - - /** \brief Default constructor. - * - * For fixed-size matrices, does nothing. - * - * For dynamic-size matrices, creates an empty matrix of size 0. Does not allocate any array. Such a matrix - * is called a null matrix. This constructor is the unique way to create null matrices: resizing - * a matrix to 0 is not supported. - * - * \sa resize(Index,Index) - */ - EIGEN_STRONG_INLINE Matrix() : Base() - { - Base::_check_template_params(); - EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED - } - - // FIXME is it still needed - Matrix(internal::constructor_without_unaligned_array_assert) - : Base(internal::constructor_without_unaligned_array_assert()) - { Base::_check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } - -#ifdef EIGEN_HAVE_RVALUE_REFERENCES - Matrix(Matrix&& other) - : Base(std::move(other)) - { - Base::_check_template_params(); - if (RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic) - Base::_set_noalias(other); - } - Matrix& operator=(Matrix&& other) - { - other.swap(*this); - return *this; - } -#endif - - /** \brief Constructs a vector or row-vector with given dimension. \only_for_vectors - * - * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, - * it is redundant to pass the dimension here, so it makes more sense to use the default - * constructor Matrix() instead. - */ - EIGEN_STRONG_INLINE explicit Matrix(Index dim) - : Base(dim, RowsAtCompileTime == 1 ? 1 : dim, ColsAtCompileTime == 1 ? 1 : dim) - { - Base::_check_template_params(); - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Matrix) - eigen_assert(dim >= 0); - eigen_assert(SizeAtCompileTime == Dynamic || SizeAtCompileTime == dim); - EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED - } - - #ifndef EIGEN_PARSED_BY_DOXYGEN - template - EIGEN_STRONG_INLINE Matrix(const T0& x, const T1& y) - { - Base::_check_template_params(); - Base::template _init2(x, y); - } - #else - /** \brief Constructs an uninitialized matrix with \a rows rows and \a cols columns. - * - * This is useful for dynamic-size matrices. For fixed-size matrices, - * it is redundant to pass these parameters, so one should use the default constructor - * Matrix() instead. */ - Matrix(Index rows, Index cols); - /** \brief Constructs an initialized 2D vector with given coefficients */ - Matrix(const Scalar& x, const Scalar& y); - #endif - - /** \brief Constructs an initialized 3D vector with given coefficients */ - EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z) - { - Base::_check_template_params(); - EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 3) - m_storage.data()[0] = x; - m_storage.data()[1] = y; - m_storage.data()[2] = z; - } - /** \brief Constructs an initialized 4D vector with given coefficients */ - EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z, const Scalar& w) - { - Base::_check_template_params(); - EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 4) - m_storage.data()[0] = x; - m_storage.data()[1] = y; - m_storage.data()[2] = z; - m_storage.data()[3] = w; - } - - explicit Matrix(const Scalar *data); - - /** \brief Constructor copying the value of the expression \a other */ - template - EIGEN_STRONG_INLINE Matrix(const MatrixBase& other) - : Base(other.rows() * other.cols(), other.rows(), other.cols()) - { - // This test resides here, to bring the error messages closer to the user. Normally, these checks - // are performed deeply within the library, thus causing long and scary error traces. - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - - Base::_check_template_params(); - Base::_set_noalias(other); - } - /** \brief Copy constructor */ - EIGEN_STRONG_INLINE Matrix(const Matrix& other) - : Base(other.rows() * other.cols(), other.rows(), other.cols()) - { - Base::_check_template_params(); - Base::_set_noalias(other); - } - /** \brief Copy constructor with in-place evaluation */ - template - EIGEN_STRONG_INLINE Matrix(const ReturnByValue& other) - { - Base::_check_template_params(); - Base::resize(other.rows(), other.cols()); - other.evalTo(*this); - } - - /** \brief Copy constructor for generic expressions. - * \sa MatrixBase::operator=(const EigenBase&) - */ - template - EIGEN_STRONG_INLINE Matrix(const EigenBase &other) - : Base(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols()) - { - Base::_check_template_params(); - Base::_resize_to_match(other); - // FIXME/CHECK: isn't *this = other.derived() more efficient. it allows to - // go for pure _set() implementations, right? - *this = other; - } - - /** \internal - * \brief Override MatrixBase::swap() since for dynamic-sized matrices - * of same type it is enough to swap the data pointers. - */ - template - void swap(MatrixBase const & other) - { this->_swap(other.derived()); } - - inline Index innerStride() const { return 1; } - inline Index outerStride() const { return this->innerSize(); } - - /////////// Geometry module /////////// - - template - explicit Matrix(const RotationBase& r); - template - Matrix& operator=(const RotationBase& r); - - #ifdef EIGEN2_SUPPORT - template - explicit Matrix(const eigen2_RotationBase& r); - template - Matrix& operator=(const eigen2_RotationBase& r); - #endif - - // allow to extend Matrix outside Eigen - #ifdef EIGEN_MATRIX_PLUGIN - #include EIGEN_MATRIX_PLUGIN - #endif - - protected: - template - friend struct internal::conservative_resize_like_impl; - - using Base::m_storage; -}; - -/** \defgroup matrixtypedefs Global matrix typedefs - * - * \ingroup Core_Module - * - * Eigen defines several typedef shortcuts for most common matrix and vector types. - * - * The general patterns are the following: - * - * \c MatrixSizeType where \c Size can be \c 2,\c 3,\c 4 for fixed size square matrices or \c X for dynamic size, - * and where \c Type can be \c i for integer, \c f for float, \c d for double, \c cf for complex float, \c cd - * for complex double. - * - * For example, \c Matrix3d is a fixed-size 3x3 matrix type of doubles, and \c MatrixXf is a dynamic-size matrix of floats. - * - * There are also \c VectorSizeType and \c RowVectorSizeType which are self-explanatory. For example, \c Vector4cf is - * a fixed-size vector of 4 complex floats. - * - * \sa class Matrix - */ - -#define EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Size, SizeSuffix) \ -/** \ingroup matrixtypedefs */ \ -typedef Matrix Matrix##SizeSuffix##TypeSuffix; \ -/** \ingroup matrixtypedefs */ \ -typedef Matrix Vector##SizeSuffix##TypeSuffix; \ -/** \ingroup matrixtypedefs */ \ -typedef Matrix RowVector##SizeSuffix##TypeSuffix; - -#define EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, Size) \ -/** \ingroup matrixtypedefs */ \ -typedef Matrix Matrix##Size##X##TypeSuffix; \ -/** \ingroup matrixtypedefs */ \ -typedef Matrix Matrix##X##Size##TypeSuffix; - -#define EIGEN_MAKE_TYPEDEFS_ALL_SIZES(Type, TypeSuffix) \ -EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 2, 2) \ -EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 3, 3) \ -EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 4, 4) \ -EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Dynamic, X) \ -EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 2) \ -EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 3) \ -EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 4) - -EIGEN_MAKE_TYPEDEFS_ALL_SIZES(int, i) -EIGEN_MAKE_TYPEDEFS_ALL_SIZES(float, f) -EIGEN_MAKE_TYPEDEFS_ALL_SIZES(double, d) -EIGEN_MAKE_TYPEDEFS_ALL_SIZES(std::complex, cf) -EIGEN_MAKE_TYPEDEFS_ALL_SIZES(std::complex, cd) - -#undef EIGEN_MAKE_TYPEDEFS_ALL_SIZES -#undef EIGEN_MAKE_TYPEDEFS -#undef EIGEN_MAKE_FIXED_TYPEDEFS - -} // end namespace Eigen - -#endif // EIGEN_MATRIX_H diff --git a/splinter/src/Core/MatrixBase.h b/splinter/src/Core/MatrixBase.h deleted file mode 100644 index e83ef4dc05..0000000000 --- a/splinter/src/Core/MatrixBase.h +++ /dev/null @@ -1,563 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2009 Benoit Jacob -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_MATRIXBASE_H -#define EIGEN_MATRIXBASE_H - -namespace Eigen { - -/** \class MatrixBase - * \ingroup Core_Module - * - * \brief Base class for all dense matrices, vectors, and expressions - * - * This class is the base that is inherited by all matrix, vector, and related expression - * types. Most of the Eigen API is contained in this class, and its base classes. Other important - * classes for the Eigen API are Matrix, and VectorwiseOp. - * - * Note that some methods are defined in other modules such as the \ref LU_Module LU module - * for all functions related to matrix inversions. - * - * \tparam Derived is the derived type, e.g. a matrix type, or an expression, etc. - * - * When writing a function taking Eigen objects as argument, if you want your function - * to take as argument any matrix, vector, or expression, just let it take a - * MatrixBase argument. As an example, here is a function printFirstRow which, given - * a matrix, vector, or expression \a x, prints the first row of \a x. - * - * \code - template - void printFirstRow(const Eigen::MatrixBase& x) - { - cout << x.row(0) << endl; - } - * \endcode - * - * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_MATRIXBASE_PLUGIN. - * - * \sa \ref TopicClassHierarchy - */ -template class MatrixBase - : public DenseBase -{ - public: -#ifndef EIGEN_PARSED_BY_DOXYGEN - typedef MatrixBase StorageBaseType; - typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; - typedef typename internal::traits::Scalar Scalar; - typedef typename internal::packet_traits::type PacketScalar; - typedef typename NumTraits::Real RealScalar; - - typedef DenseBase Base; - using Base::RowsAtCompileTime; - using Base::ColsAtCompileTime; - using Base::SizeAtCompileTime; - using Base::MaxRowsAtCompileTime; - using Base::MaxColsAtCompileTime; - using Base::MaxSizeAtCompileTime; - using Base::IsVectorAtCompileTime; - using Base::Flags; - using Base::CoeffReadCost; - - using Base::derived; - using Base::const_cast_derived; - using Base::rows; - using Base::cols; - using Base::size; - using Base::coeff; - using Base::coeffRef; - using Base::lazyAssign; - using Base::eval; - using Base::operator+=; - using Base::operator-=; - using Base::operator*=; - using Base::operator/=; - - typedef typename Base::CoeffReturnType CoeffReturnType; - typedef typename Base::ConstTransposeReturnType ConstTransposeReturnType; - typedef typename Base::RowXpr RowXpr; - typedef typename Base::ColXpr ColXpr; -#endif // not EIGEN_PARSED_BY_DOXYGEN - - - -#ifndef EIGEN_PARSED_BY_DOXYGEN - /** type of the equivalent square matrix */ - typedef Matrix SquareMatrixType; -#endif // not EIGEN_PARSED_BY_DOXYGEN - - /** \returns the size of the main diagonal, which is min(rows(),cols()). - * \sa rows(), cols(), SizeAtCompileTime. */ - inline Index diagonalSize() const { return (std::min)(rows(),cols()); } - - /** \brief The plain matrix type corresponding to this expression. - * - * This is not necessarily exactly the return type of eval(). In the case of plain matrices, - * the return type of eval() is a const reference to a matrix, not a matrix! It is however guaranteed - * that the return type of eval() is either PlainObject or const PlainObject&. - */ - typedef Matrix::Scalar, - internal::traits::RowsAtCompileTime, - internal::traits::ColsAtCompileTime, - AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), - internal::traits::MaxRowsAtCompileTime, - internal::traits::MaxColsAtCompileTime - > PlainObject; - -#ifndef EIGEN_PARSED_BY_DOXYGEN - /** \internal Represents a matrix with all coefficients equal to one another*/ - typedef CwiseNullaryOp,Derived> ConstantReturnType; - /** \internal the return type of MatrixBase::adjoint() */ - typedef typename internal::conditional::IsComplex, - CwiseUnaryOp, ConstTransposeReturnType>, - ConstTransposeReturnType - >::type AdjointReturnType; - /** \internal Return type of eigenvalues() */ - typedef Matrix, internal::traits::ColsAtCompileTime, 1, ColMajor> EigenvaluesReturnType; - /** \internal the return type of identity */ - typedef CwiseNullaryOp,Derived> IdentityReturnType; - /** \internal the return type of unit vectors */ - typedef Block, SquareMatrixType>, - internal::traits::RowsAtCompileTime, - internal::traits::ColsAtCompileTime> BasisReturnType; -#endif // not EIGEN_PARSED_BY_DOXYGEN - -#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::MatrixBase -# include "../plugins/CommonCwiseUnaryOps.h" -# include "../plugins/CommonCwiseBinaryOps.h" -# include "../plugins/MatrixCwiseUnaryOps.h" -# include "../plugins/MatrixCwiseBinaryOps.h" -# ifdef EIGEN_MATRIXBASE_PLUGIN -# include EIGEN_MATRIXBASE_PLUGIN -# endif -#undef EIGEN_CURRENT_STORAGE_BASE_CLASS - - /** Special case of the template operator=, in order to prevent the compiler - * from generating a default operator= (issue hit with g++ 4.1) - */ - Derived& operator=(const MatrixBase& other); - - // We cannot inherit here via Base::operator= since it is causing - // trouble with MSVC. - - template - Derived& operator=(const DenseBase& other); - - template - Derived& operator=(const EigenBase& other); - - template - Derived& operator=(const ReturnByValue& other); - - template - Derived& lazyAssign(const ProductBase& other); - - template - Derived& lazyAssign(const MatrixPowerProduct& other); - - template - Derived& operator+=(const MatrixBase& other); - template - Derived& operator-=(const MatrixBase& other); - - template - const typename ProductReturnType::Type - operator*(const MatrixBase &other) const; - - template - const typename LazyProductReturnType::Type - lazyProduct(const MatrixBase &other) const; - - template - Derived& operator*=(const EigenBase& other); - - template - void applyOnTheLeft(const EigenBase& other); - - template - void applyOnTheRight(const EigenBase& other); - - template - const DiagonalProduct - operator*(const DiagonalBase &diagonal) const; - - template - typename internal::scalar_product_traits::Scalar,typename internal::traits::Scalar>::ReturnType - dot(const MatrixBase& other) const; - - #ifdef EIGEN2_SUPPORT - template - Scalar eigen2_dot(const MatrixBase& other) const; - #endif - - RealScalar squaredNorm() const; - RealScalar norm() const; - RealScalar stableNorm() const; - RealScalar blueNorm() const; - RealScalar hypotNorm() const; - const PlainObject normalized() const; - void normalize(); - - const AdjointReturnType adjoint() const; - void adjointInPlace(); - - typedef Diagonal DiagonalReturnType; - DiagonalReturnType diagonal(); - typedef typename internal::add_const >::type ConstDiagonalReturnType; - ConstDiagonalReturnType diagonal() const; - - template struct DiagonalIndexReturnType { typedef Diagonal Type; }; - template struct ConstDiagonalIndexReturnType { typedef const Diagonal Type; }; - - template typename DiagonalIndexReturnType::Type diagonal(); - template typename ConstDiagonalIndexReturnType::Type diagonal() const; - - typedef Diagonal DiagonalDynamicIndexReturnType; - typedef typename internal::add_const >::type ConstDiagonalDynamicIndexReturnType; - - DiagonalDynamicIndexReturnType diagonal(Index index); - ConstDiagonalDynamicIndexReturnType diagonal(Index index) const; - - #ifdef EIGEN2_SUPPORT - template typename internal::eigen2_part_return_type::type part(); - template const typename internal::eigen2_part_return_type::type part() const; - - // huuuge hack. make Eigen2's matrix.part() work in eigen3. Problem: Diagonal is now a class template instead - // of an integer constant. Solution: overload the part() method template wrt template parameters list. - template class U> - const DiagonalWrapper part() const - { return diagonal().asDiagonal(); } - #endif // EIGEN2_SUPPORT - - template struct TriangularViewReturnType { typedef TriangularView Type; }; - template struct ConstTriangularViewReturnType { typedef const TriangularView Type; }; - - template typename TriangularViewReturnType::Type triangularView(); - template typename ConstTriangularViewReturnType::Type triangularView() const; - - template struct SelfAdjointViewReturnType { typedef SelfAdjointView Type; }; - template struct ConstSelfAdjointViewReturnType { typedef const SelfAdjointView Type; }; - - template typename SelfAdjointViewReturnType::Type selfadjointView(); - template typename ConstSelfAdjointViewReturnType::Type selfadjointView() const; - - const SparseView sparseView(const Scalar& m_reference = Scalar(0), - const typename NumTraits::Real& m_epsilon = NumTraits::dummy_precision()) const; - static const IdentityReturnType Identity(); - static const IdentityReturnType Identity(Index rows, Index cols); - static const BasisReturnType Unit(Index size, Index i); - static const BasisReturnType Unit(Index i); - static const BasisReturnType UnitX(); - static const BasisReturnType UnitY(); - static const BasisReturnType UnitZ(); - static const BasisReturnType UnitW(); - - const DiagonalWrapper asDiagonal() const; - const PermutationWrapper asPermutation() const; - - Derived& setIdentity(); - Derived& setIdentity(Index rows, Index cols); - - bool isIdentity(const RealScalar& prec = NumTraits::dummy_precision()) const; - bool isDiagonal(const RealScalar& prec = NumTraits::dummy_precision()) const; - - bool isUpperTriangular(const RealScalar& prec = NumTraits::dummy_precision()) const; - bool isLowerTriangular(const RealScalar& prec = NumTraits::dummy_precision()) const; - - template - bool isOrthogonal(const MatrixBase& other, - const RealScalar& prec = NumTraits::dummy_precision()) const; - bool isUnitary(const RealScalar& prec = NumTraits::dummy_precision()) const; - - /** \returns true if each coefficients of \c *this and \a other are all exactly equal. - * \warning When using floating point scalar values you probably should rather use a - * fuzzy comparison such as isApprox() - * \sa isApprox(), operator!= */ - template - inline bool operator==(const MatrixBase& other) const - { return cwiseEqual(other).all(); } - - /** \returns true if at least one pair of coefficients of \c *this and \a other are not exactly equal to each other. - * \warning When using floating point scalar values you probably should rather use a - * fuzzy comparison such as isApprox() - * \sa isApprox(), operator== */ - template - inline bool operator!=(const MatrixBase& other) const - { return cwiseNotEqual(other).any(); } - - NoAlias noalias(); - - inline const ForceAlignedAccess forceAlignedAccess() const; - inline ForceAlignedAccess forceAlignedAccess(); - template inline typename internal::add_const_on_value_type,Derived&>::type>::type forceAlignedAccessIf() const; - template inline typename internal::conditional,Derived&>::type forceAlignedAccessIf(); - - Scalar trace() const; - -/////////// Array module /////////// - - template RealScalar lpNorm() const; - - MatrixBase& matrix() { return *this; } - const MatrixBase& matrix() const { return *this; } - - /** \returns an \link Eigen::ArrayBase Array \endlink expression of this matrix - * \sa ArrayBase::matrix() */ - ArrayWrapper array() { return derived(); } - const ArrayWrapper array() const { return derived(); } - -/////////// LU module /////////// - - const FullPivLU fullPivLu() const; - const PartialPivLU partialPivLu() const; - - #if EIGEN2_SUPPORT_STAGE < STAGE20_RESOLVE_API_CONFLICTS - const LU lu() const; - #endif - - #ifdef EIGEN2_SUPPORT - const LU eigen2_lu() const; - #endif - - #if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS - const PartialPivLU lu() const; - #endif - - #ifdef EIGEN2_SUPPORT - template - void computeInverse(MatrixBase *result) const { - *result = this->inverse(); - } - #endif - - const internal::inverse_impl inverse() const; - template - void computeInverseAndDetWithCheck( - ResultType& inverse, - typename ResultType::Scalar& determinant, - bool& invertible, - const RealScalar& absDeterminantThreshold = NumTraits::dummy_precision() - ) const; - template - void computeInverseWithCheck( - ResultType& inverse, - bool& invertible, - const RealScalar& absDeterminantThreshold = NumTraits::dummy_precision() - ) const; - Scalar determinant() const; - -/////////// Cholesky module /////////// - - const LLT llt() const; - const LDLT ldlt() const; - -/////////// QR module /////////// - - const HouseholderQR householderQr() const; - const ColPivHouseholderQR colPivHouseholderQr() const; - const FullPivHouseholderQR fullPivHouseholderQr() const; - - #ifdef EIGEN2_SUPPORT - const QR qr() const; - #endif - - EigenvaluesReturnType eigenvalues() const; - RealScalar operatorNorm() const; - -/////////// SVD module /////////// - - JacobiSVD jacobiSvd(unsigned int computationOptions = 0) const; - - #ifdef EIGEN2_SUPPORT - SVD svd() const; - #endif - -/////////// Geometry module /////////// - - #ifndef EIGEN_PARSED_BY_DOXYGEN - /// \internal helper struct to form the return type of the cross product - template struct cross_product_return_type { - typedef typename internal::scalar_product_traits::Scalar,typename internal::traits::Scalar>::ReturnType Scalar; - typedef Matrix type; - }; - #endif // EIGEN_PARSED_BY_DOXYGEN - template - typename cross_product_return_type::type - cross(const MatrixBase& other) const; - template - PlainObject cross3(const MatrixBase& other) const; - PlainObject unitOrthogonal(void) const; - Matrix eulerAngles(Index a0, Index a1, Index a2) const; - - #if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS - ScalarMultipleReturnType operator*(const UniformScaling& s) const; - // put this as separate enum value to work around possible GCC 4.3 bug (?) - enum { HomogeneousReturnTypeDirection = ColsAtCompileTime==1?Vertical:Horizontal }; - typedef Homogeneous HomogeneousReturnType; - HomogeneousReturnType homogeneous() const; - #endif - - enum { - SizeMinusOne = SizeAtCompileTime==Dynamic ? Dynamic : SizeAtCompileTime-1 - }; - typedef Block::ColsAtCompileTime==1 ? SizeMinusOne : 1, - internal::traits::ColsAtCompileTime==1 ? 1 : SizeMinusOne> ConstStartMinusOne; - typedef CwiseUnaryOp::Scalar>, - const ConstStartMinusOne > HNormalizedReturnType; - - const HNormalizedReturnType hnormalized() const; - -////////// Householder module /////////// - - void makeHouseholderInPlace(Scalar& tau, RealScalar& beta); - template - void makeHouseholder(EssentialPart& essential, - Scalar& tau, RealScalar& beta) const; - template - void applyHouseholderOnTheLeft(const EssentialPart& essential, - const Scalar& tau, - Scalar* workspace); - template - void applyHouseholderOnTheRight(const EssentialPart& essential, - const Scalar& tau, - Scalar* workspace); - -///////// Jacobi module ///////// - - template - void applyOnTheLeft(Index p, Index q, const JacobiRotation& j); - template - void applyOnTheRight(Index p, Index q, const JacobiRotation& j); - -///////// SparseCore module ///////// - - template - EIGEN_STRONG_INLINE const typename SparseMatrixBase::template CwiseProductDenseReturnType::Type - cwiseProduct(const SparseMatrixBase &other) const - { - return other.cwiseProduct(derived()); - } - -///////// MatrixFunctions module ///////// - - typedef typename internal::stem_function::type StemFunction; - const MatrixExponentialReturnValue exp() const; - const MatrixFunctionReturnValue matrixFunction(StemFunction f) const; - const MatrixFunctionReturnValue cosh() const; - const MatrixFunctionReturnValue sinh() const; - const MatrixFunctionReturnValue cos() const; - const MatrixFunctionReturnValue sin() const; - const MatrixSquareRootReturnValue sqrt() const; - const MatrixLogarithmReturnValue log() const; - const MatrixPowerReturnValue pow(const RealScalar& p) const; - -#ifdef EIGEN2_SUPPORT - template - Derived& operator+=(const Flagged, 0, - EvalBeforeAssigningBit>& other); - - template - Derived& operator-=(const Flagged, 0, - EvalBeforeAssigningBit>& other); - - /** \deprecated because .lazy() is deprecated - * Overloaded for cache friendly product evaluation */ - template - Derived& lazyAssign(const Flagged& other) - { return lazyAssign(other._expression()); } - - template - const Flagged marked() const; - const Flagged lazy() const; - - inline const Cwise cwise() const; - inline Cwise cwise(); - - VectorBlock start(Index size); - const VectorBlock start(Index size) const; - VectorBlock end(Index size); - const VectorBlock end(Index size) const; - template VectorBlock start(); - template const VectorBlock start() const; - template VectorBlock end(); - template const VectorBlock end() const; - - Minor minor(Index row, Index col); - const Minor minor(Index row, Index col) const; -#endif - - protected: - MatrixBase() : Base() {} - - private: - explicit MatrixBase(int); - MatrixBase(int,int); - template explicit MatrixBase(const MatrixBase&); - protected: - // mixing arrays and matrices is not legal - template Derived& operator+=(const ArrayBase& ) - {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} - // mixing arrays and matrices is not legal - template Derived& operator-=(const ArrayBase& ) - {EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar))==-1,YOU_CANNOT_MIX_ARRAYS_AND_MATRICES); return *this;} -}; - - -/*************************************************************************** -* Implementation of matrix base methods -***************************************************************************/ - -/** replaces \c *this by \c *this * \a other. - * - * \returns a reference to \c *this - * - * Example: \include MatrixBase_applyOnTheRight.cpp - * Output: \verbinclude MatrixBase_applyOnTheRight.out - */ -template -template -inline Derived& -MatrixBase::operator*=(const EigenBase &other) -{ - other.derived().applyThisOnTheRight(derived()); - return derived(); -} - -/** replaces \c *this by \c *this * \a other. It is equivalent to MatrixBase::operator*=(). - * - * Example: \include MatrixBase_applyOnTheRight.cpp - * Output: \verbinclude MatrixBase_applyOnTheRight.out - */ -template -template -inline void MatrixBase::applyOnTheRight(const EigenBase &other) -{ - other.derived().applyThisOnTheRight(derived()); -} - -/** replaces \c *this by \a other * \c *this. - * - * Example: \include MatrixBase_applyOnTheLeft.cpp - * Output: \verbinclude MatrixBase_applyOnTheLeft.out - */ -template -template -inline void MatrixBase::applyOnTheLeft(const EigenBase &other) -{ - other.derived().applyThisOnTheLeft(derived()); -} - -} // end namespace Eigen - -#endif // EIGEN_MATRIXBASE_H diff --git a/splinter/src/Core/NestByValue.h b/splinter/src/Core/NestByValue.h deleted file mode 100644 index a893b1761b..0000000000 --- a/splinter/src/Core/NestByValue.h +++ /dev/null @@ -1,111 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_NESTBYVALUE_H -#define EIGEN_NESTBYVALUE_H - -namespace Eigen { - -/** \class NestByValue - * \ingroup Core_Module - * - * \brief Expression which must be nested by value - * - * \param ExpressionType the type of the object of which we are requiring nesting-by-value - * - * This class is the return type of MatrixBase::nestByValue() - * and most of the time this is the only way it is used. - * - * \sa MatrixBase::nestByValue() - */ - -namespace internal { -template -struct traits > : public traits -{}; -} - -template class NestByValue - : public internal::dense_xpr_base< NestByValue >::type -{ - public: - - typedef typename internal::dense_xpr_base::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(NestByValue) - - inline NestByValue(const ExpressionType& matrix) : m_expression(matrix) {} - - inline Index rows() const { return m_expression.rows(); } - inline Index cols() const { return m_expression.cols(); } - inline Index outerStride() const { return m_expression.outerStride(); } - inline Index innerStride() const { return m_expression.innerStride(); } - - inline const CoeffReturnType coeff(Index row, Index col) const - { - return m_expression.coeff(row, col); - } - - inline Scalar& coeffRef(Index row, Index col) - { - return m_expression.const_cast_derived().coeffRef(row, col); - } - - inline const CoeffReturnType coeff(Index index) const - { - return m_expression.coeff(index); - } - - inline Scalar& coeffRef(Index index) - { - return m_expression.const_cast_derived().coeffRef(index); - } - - template - inline const PacketScalar packet(Index row, Index col) const - { - return m_expression.template packet(row, col); - } - - template - inline void writePacket(Index row, Index col, const PacketScalar& x) - { - m_expression.const_cast_derived().template writePacket(row, col, x); - } - - template - inline const PacketScalar packet(Index index) const - { - return m_expression.template packet(index); - } - - template - inline void writePacket(Index index, const PacketScalar& x) - { - m_expression.const_cast_derived().template writePacket(index, x); - } - - operator const ExpressionType&() const { return m_expression; } - - protected: - const ExpressionType m_expression; -}; - -/** \returns an expression of the temporary version of *this. - */ -template -inline const NestByValue -DenseBase::nestByValue() const -{ - return NestByValue(derived()); -} - -} // end namespace Eigen - -#endif // EIGEN_NESTBYVALUE_H diff --git a/splinter/src/Core/NoAlias.h b/splinter/src/Core/NoAlias.h deleted file mode 100644 index 768bfb18ca..0000000000 --- a/splinter/src/Core/NoAlias.h +++ /dev/null @@ -1,134 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_NOALIAS_H -#define EIGEN_NOALIAS_H - -namespace Eigen { - -/** \class NoAlias - * \ingroup Core_Module - * - * \brief Pseudo expression providing an operator = assuming no aliasing - * - * \param ExpressionType the type of the object on which to do the lazy assignment - * - * This class represents an expression with special assignment operators - * assuming no aliasing between the target expression and the source expression. - * More precisely it alloas to bypass the EvalBeforeAssignBit flag of the source expression. - * It is the return type of MatrixBase::noalias() - * and most of the time this is the only way it is used. - * - * \sa MatrixBase::noalias() - */ -template class StorageBase> -class NoAlias -{ - typedef typename ExpressionType::Scalar Scalar; - public: - NoAlias(ExpressionType& expression) : m_expression(expression) {} - - /** Behaves like MatrixBase::lazyAssign(other) - * \sa MatrixBase::lazyAssign() */ - template - EIGEN_STRONG_INLINE ExpressionType& operator=(const StorageBase& other) - { return internal::assign_selector::run(m_expression,other.derived()); } - - /** \sa MatrixBase::operator+= */ - template - EIGEN_STRONG_INLINE ExpressionType& operator+=(const StorageBase& other) - { - typedef SelfCwiseBinaryOp, ExpressionType, OtherDerived> SelfAdder; - SelfAdder tmp(m_expression); - typedef typename internal::nested::type OtherDerivedNested; - typedef typename internal::remove_all::type _OtherDerivedNested; - internal::assign_selector::run(tmp,OtherDerivedNested(other.derived())); - return m_expression; - } - - /** \sa MatrixBase::operator-= */ - template - EIGEN_STRONG_INLINE ExpressionType& operator-=(const StorageBase& other) - { - typedef SelfCwiseBinaryOp, ExpressionType, OtherDerived> SelfAdder; - SelfAdder tmp(m_expression); - typedef typename internal::nested::type OtherDerivedNested; - typedef typename internal::remove_all::type _OtherDerivedNested; - internal::assign_selector::run(tmp,OtherDerivedNested(other.derived())); - return m_expression; - } - -#ifndef EIGEN_PARSED_BY_DOXYGEN - template - EIGEN_STRONG_INLINE ExpressionType& operator+=(const ProductBase& other) - { other.derived().addTo(m_expression); return m_expression; } - - template - EIGEN_STRONG_INLINE ExpressionType& operator-=(const ProductBase& other) - { other.derived().subTo(m_expression); return m_expression; } - - template - EIGEN_STRONG_INLINE ExpressionType& operator+=(const CoeffBasedProduct& other) - { return m_expression.derived() += CoeffBasedProduct(other.lhs(), other.rhs()); } - - template - EIGEN_STRONG_INLINE ExpressionType& operator-=(const CoeffBasedProduct& other) - { return m_expression.derived() -= CoeffBasedProduct(other.lhs(), other.rhs()); } - - template - ExpressionType& operator=(const ReturnByValue& func) - { return m_expression = func; } -#endif - - ExpressionType& expression() const - { - return m_expression; - } - - protected: - ExpressionType& m_expression; -}; - -/** \returns a pseudo expression of \c *this with an operator= assuming - * no aliasing between \c *this and the source expression. - * - * More precisely, noalias() allows to bypass the EvalBeforeAssignBit flag. - * Currently, even though several expressions may alias, only product - * expressions have this flag. Therefore, noalias() is only usefull when - * the source expression contains a matrix product. - * - * Here are some examples where noalias is usefull: - * \code - * D.noalias() = A * B; - * D.noalias() += A.transpose() * B; - * D.noalias() -= 2 * A * B.adjoint(); - * \endcode - * - * On the other hand the following example will lead to a \b wrong result: - * \code - * A.noalias() = A * B; - * \endcode - * because the result matrix A is also an operand of the matrix product. Therefore, - * there is no alternative than evaluating A * B in a temporary, that is the default - * behavior when you write: - * \code - * A = A * B; - * \endcode - * - * \sa class NoAlias - */ -template -NoAlias MatrixBase::noalias() -{ - return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_NOALIAS_H diff --git a/splinter/src/Core/NumTraits.h b/splinter/src/Core/NumTraits.h deleted file mode 100644 index bac9e50b85..0000000000 --- a/splinter/src/Core/NumTraits.h +++ /dev/null @@ -1,150 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2010 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_NUMTRAITS_H -#define EIGEN_NUMTRAITS_H - -namespace Eigen { - -/** \class NumTraits - * \ingroup Core_Module - * - * \brief Holds information about the various numeric (i.e. scalar) types allowed by Eigen. - * - * \param T the numeric type at hand - * - * This class stores enums, typedefs and static methods giving information about a numeric type. - * - * The provided data consists of: - * \li A typedef \a Real, giving the "real part" type of \a T. If \a T is already real, - * then \a Real is just a typedef to \a T. If \a T is \c std::complex then \a Real - * is a typedef to \a U. - * \li A typedef \a NonInteger, giving the type that should be used for operations producing non-integral values, - * such as quotients, square roots, etc. If \a T is a floating-point type, then this typedef just gives - * \a T again. Note however that many Eigen functions such as internal::sqrt simply refuse to - * take integers. Outside of a few cases, Eigen doesn't do automatic type promotion. Thus, this typedef is - * only intended as a helper for code that needs to explicitly promote types. - * \li A typedef \a Nested giving the type to use to nest a value inside of the expression tree. If you don't know what - * this means, just use \a T here. - * \li An enum value \a IsComplex. It is equal to 1 if \a T is a \c std::complex - * type, and to 0 otherwise. - * \li An enum value \a IsInteger. It is equal to \c 1 if \a T is an integer type such as \c int, - * and to \c 0 otherwise. - * \li Enum values ReadCost, AddCost and MulCost representing a rough estimate of the number of CPU cycles needed - * to by move / add / mul instructions respectively, assuming the data is already stored in CPU registers. - * Stay vague here. No need to do architecture-specific stuff. - * \li An enum value \a IsSigned. It is equal to \c 1 if \a T is a signed type and to 0 if \a T is unsigned. - * \li An enum value \a RequireInitialization. It is equal to \c 1 if the constructor of the numeric type \a T must - * be called, and to 0 if it is safe not to call it. Default is 0 if \a T is an arithmetic type, and 1 otherwise. - * \li An epsilon() function which, unlike std::numeric_limits::epsilon(), returns a \a Real instead of a \a T. - * \li A dummy_precision() function returning a weak epsilon value. It is mainly used as a default - * value by the fuzzy comparison operators. - * \li highest() and lowest() functions returning the highest and lowest possible values respectively. - */ - -template struct GenericNumTraits -{ - enum { - IsInteger = std::numeric_limits::is_integer, - IsSigned = std::numeric_limits::is_signed, - IsComplex = 0, - RequireInitialization = internal::is_arithmetic::value ? 0 : 1, - ReadCost = 1, - AddCost = 1, - MulCost = 1 - }; - - typedef T Real; - typedef typename internal::conditional< - IsInteger, - typename internal::conditional::type, - T - >::type NonInteger; - typedef T Nested; - - static inline Real epsilon() { return std::numeric_limits::epsilon(); } - static inline Real dummy_precision() - { - // make sure to override this for floating-point types - return Real(0); - } - static inline T highest() { return (std::numeric_limits::max)(); } - static inline T lowest() { return IsInteger ? (std::numeric_limits::min)() : (-(std::numeric_limits::max)()); } - -#ifdef EIGEN2_SUPPORT - enum { - HasFloatingPoint = !IsInteger - }; - typedef NonInteger FloatingPoint; -#endif -}; - -template struct NumTraits : GenericNumTraits -{}; - -template<> struct NumTraits - : GenericNumTraits -{ - static inline float dummy_precision() { return 1e-5f; } -}; - -template<> struct NumTraits : GenericNumTraits -{ - static inline double dummy_precision() { return 1e-12; } -}; - -template<> struct NumTraits - : GenericNumTraits -{ - static inline long double dummy_precision() { return 1e-15l; } -}; - -template struct NumTraits > - : GenericNumTraits > -{ - typedef _Real Real; - enum { - IsComplex = 1, - RequireInitialization = NumTraits<_Real>::RequireInitialization, - ReadCost = 2 * NumTraits<_Real>::ReadCost, - AddCost = 2 * NumTraits::AddCost, - MulCost = 4 * NumTraits::MulCost + 2 * NumTraits::AddCost - }; - - static inline Real epsilon() { return NumTraits::epsilon(); } - static inline Real dummy_precision() { return NumTraits::dummy_precision(); } -}; - -template -struct NumTraits > -{ - typedef Array ArrayType; - typedef typename NumTraits::Real RealScalar; - typedef Array Real; - typedef typename NumTraits::NonInteger NonIntegerScalar; - typedef Array NonInteger; - typedef ArrayType & Nested; - - enum { - IsComplex = NumTraits::IsComplex, - IsInteger = NumTraits::IsInteger, - IsSigned = NumTraits::IsSigned, - RequireInitialization = 1, - ReadCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits::ReadCost, - AddCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits::AddCost, - MulCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits::MulCost - }; - - static inline RealScalar epsilon() { return NumTraits::epsilon(); } - static inline RealScalar dummy_precision() { return NumTraits::dummy_precision(); } -}; - -} // end namespace Eigen - -#endif // EIGEN_NUMTRAITS_H diff --git a/splinter/src/Core/PermutationMatrix.h b/splinter/src/Core/PermutationMatrix.h deleted file mode 100644 index 85ffae2653..0000000000 --- a/splinter/src/Core/PermutationMatrix.h +++ /dev/null @@ -1,721 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Benoit Jacob -// Copyright (C) 2009-2011 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_PERMUTATIONMATRIX_H -#define EIGEN_PERMUTATIONMATRIX_H - -namespace Eigen { - -template class PermutedImpl; - -/** \class PermutationBase - * \ingroup Core_Module - * - * \brief Base class for permutations - * - * \param Derived the derived class - * - * This class is the base class for all expressions representing a permutation matrix, - * internally stored as a vector of integers. - * The convention followed here is that if \f$ \sigma \f$ is a permutation, the corresponding permutation matrix - * \f$ P_\sigma \f$ is such that if \f$ (e_1,\ldots,e_p) \f$ is the canonical basis, we have: - * \f[ P_\sigma(e_i) = e_{\sigma(i)}. \f] - * This convention ensures that for any two permutations \f$ \sigma, \tau \f$, we have: - * \f[ P_{\sigma\circ\tau} = P_\sigma P_\tau. \f] - * - * Permutation matrices are square and invertible. - * - * Notice that in addition to the member functions and operators listed here, there also are non-member - * operator* to multiply any kind of permutation object with any kind of matrix expression (MatrixBase) - * on either side. - * - * \sa class PermutationMatrix, class PermutationWrapper - */ - -namespace internal { - -template -struct permut_matrix_product_retval; -template -struct permut_sparsematrix_product_retval; -enum PermPermProduct_t {PermPermProduct}; - -} // end namespace internal - -template -class PermutationBase : public EigenBase -{ - typedef internal::traits Traits; - typedef EigenBase Base; - public: - - #ifndef EIGEN_PARSED_BY_DOXYGEN - typedef typename Traits::IndicesType IndicesType; - enum { - Flags = Traits::Flags, - CoeffReadCost = Traits::CoeffReadCost, - RowsAtCompileTime = Traits::RowsAtCompileTime, - ColsAtCompileTime = Traits::ColsAtCompileTime, - MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime, - MaxColsAtCompileTime = Traits::MaxColsAtCompileTime - }; - typedef typename Traits::Scalar Scalar; - typedef typename Traits::Index Index; - typedef Matrix - DenseMatrixType; - typedef PermutationMatrix - PlainPermutationType; - using Base::derived; - #endif - - /** Copies the other permutation into *this */ - template - Derived& operator=(const PermutationBase& other) - { - indices() = other.indices(); - return derived(); - } - - /** Assignment from the Transpositions \a tr */ - template - Derived& operator=(const TranspositionsBase& tr) - { - setIdentity(tr.size()); - for(Index k=size()-1; k>=0; --k) - applyTranspositionOnTheRight(k,tr.coeff(k)); - return derived(); - } - - #ifndef EIGEN_PARSED_BY_DOXYGEN - /** This is a special case of the templated operator=. Its purpose is to - * prevent a default operator= from hiding the templated operator=. - */ - Derived& operator=(const PermutationBase& other) - { - indices() = other.indices(); - return derived(); - } - #endif - - /** \returns the number of rows */ - inline Index rows() const { return Index(indices().size()); } - - /** \returns the number of columns */ - inline Index cols() const { return Index(indices().size()); } - - /** \returns the size of a side of the respective square matrix, i.e., the number of indices */ - inline Index size() const { return Index(indices().size()); } - - #ifndef EIGEN_PARSED_BY_DOXYGEN - template - void evalTo(MatrixBase& other) const - { - other.setZero(); - for (int i=0; i=0 && j>=0 && i=0 && j>=0 && i inverse() const - { return derived(); } - /** \returns the tranpose permutation matrix. - * - * \note \note_try_to_help_rvo - */ - inline Transpose transpose() const - { return derived(); } - - /**** multiplication helpers to hopefully get RVO ****/ - - -#ifndef EIGEN_PARSED_BY_DOXYGEN - protected: - template - void assignTranspose(const PermutationBase& other) - { - for (int i=0; i - void assignProduct(const Lhs& lhs, const Rhs& rhs) - { - eigen_assert(lhs.cols() == rhs.rows()); - for (int i=0; i - inline PlainPermutationType operator*(const PermutationBase& other) const - { return PlainPermutationType(internal::PermPermProduct, derived(), other.derived()); } - - /** \returns the product of a permutation with another inverse permutation. - * - * \note \note_try_to_help_rvo - */ - template - inline PlainPermutationType operator*(const Transpose >& other) const - { return PlainPermutationType(internal::PermPermProduct, *this, other.eval()); } - - /** \returns the product of an inverse permutation with another permutation. - * - * \note \note_try_to_help_rvo - */ - template friend - inline PlainPermutationType operator*(const Transpose >& other, const PermutationBase& perm) - { return PlainPermutationType(internal::PermPermProduct, other.eval(), perm); } - - /** \returns the determinant of the permutation matrix, which is either 1 or -1 depending on the parity of the permutation. - * - * This function is O(\c n) procedure allocating a buffer of \c n booleans. - */ - Index determinant() const - { - Index res = 1; - Index n = size(); - Matrix mask(n); - mask.fill(false); - Index r = 0; - while(r < n) - { - // search for the next seed - while(r=n) - break; - // we got one, let's follow it until we are back to the seed - Index k0 = r++; - mask.coeffRef(k0) = true; - for(Index k=indices().coeff(k0); k!=k0; k=indices().coeff(k)) - { - mask.coeffRef(k) = true; - res = -res; - } - } - return res; - } - - protected: - -}; - -/** \class PermutationMatrix - * \ingroup Core_Module - * - * \brief Permutation matrix - * - * \param SizeAtCompileTime the number of rows/cols, or Dynamic - * \param MaxSizeAtCompileTime the maximum number of rows/cols, or Dynamic. This optional parameter defaults to SizeAtCompileTime. Most of the time, you should not have to specify it. - * \param IndexType the interger type of the indices - * - * This class represents a permutation matrix, internally stored as a vector of integers. - * - * \sa class PermutationBase, class PermutationWrapper, class DiagonalMatrix - */ - -namespace internal { -template -struct traits > - : traits > -{ - typedef IndexType Index; - typedef Matrix IndicesType; -}; -} - -template -class PermutationMatrix : public PermutationBase > -{ - typedef PermutationBase Base; - typedef internal::traits Traits; - public: - - #ifndef EIGEN_PARSED_BY_DOXYGEN - typedef typename Traits::IndicesType IndicesType; - #endif - - inline PermutationMatrix() - {} - - /** Constructs an uninitialized permutation matrix of given size. - */ - inline PermutationMatrix(int size) : m_indices(size) - {} - - /** Copy constructor. */ - template - inline PermutationMatrix(const PermutationBase& other) - : m_indices(other.indices()) {} - - #ifndef EIGEN_PARSED_BY_DOXYGEN - /** Standard copy constructor. Defined only to prevent a default copy constructor - * from hiding the other templated constructor */ - inline PermutationMatrix(const PermutationMatrix& other) : m_indices(other.indices()) {} - #endif - - /** Generic constructor from expression of the indices. The indices - * array has the meaning that the permutations sends each integer i to indices[i]. - * - * \warning It is your responsibility to check that the indices array that you passes actually - * describes a permutation, i.e., each value between 0 and n-1 occurs exactly once, where n is the - * array's size. - */ - template - explicit inline PermutationMatrix(const MatrixBase& a_indices) : m_indices(a_indices) - {} - - /** Convert the Transpositions \a tr to a permutation matrix */ - template - explicit PermutationMatrix(const TranspositionsBase& tr) - : m_indices(tr.size()) - { - *this = tr; - } - - /** Copies the other permutation into *this */ - template - PermutationMatrix& operator=(const PermutationBase& other) - { - m_indices = other.indices(); - return *this; - } - - /** Assignment from the Transpositions \a tr */ - template - PermutationMatrix& operator=(const TranspositionsBase& tr) - { - return Base::operator=(tr.derived()); - } - - #ifndef EIGEN_PARSED_BY_DOXYGEN - /** This is a special case of the templated operator=. Its purpose is to - * prevent a default operator= from hiding the templated operator=. - */ - PermutationMatrix& operator=(const PermutationMatrix& other) - { - m_indices = other.m_indices; - return *this; - } - #endif - - /** const version of indices(). */ - const IndicesType& indices() const { return m_indices; } - /** \returns a reference to the stored array representing the permutation. */ - IndicesType& indices() { return m_indices; } - - - /**** multiplication helpers to hopefully get RVO ****/ - -#ifndef EIGEN_PARSED_BY_DOXYGEN - template - PermutationMatrix(const Transpose >& other) - : m_indices(other.nestedPermutation().size()) - { - for (int i=0; i - PermutationMatrix(internal::PermPermProduct_t, const Lhs& lhs, const Rhs& rhs) - : m_indices(lhs.indices().size()) - { - Base::assignProduct(lhs,rhs); - } -#endif - - protected: - - IndicesType m_indices; -}; - - -namespace internal { -template -struct traits,_PacketAccess> > - : traits > -{ - typedef IndexType Index; - typedef Map, _PacketAccess> IndicesType; -}; -} - -template -class Map,_PacketAccess> - : public PermutationBase,_PacketAccess> > -{ - typedef PermutationBase Base; - typedef internal::traits Traits; - public: - - #ifndef EIGEN_PARSED_BY_DOXYGEN - typedef typename Traits::IndicesType IndicesType; - typedef typename IndicesType::Scalar Index; - #endif - - inline Map(const Index* indicesPtr) - : m_indices(indicesPtr) - {} - - inline Map(const Index* indicesPtr, Index size) - : m_indices(indicesPtr,size) - {} - - /** Copies the other permutation into *this */ - template - Map& operator=(const PermutationBase& other) - { return Base::operator=(other.derived()); } - - /** Assignment from the Transpositions \a tr */ - template - Map& operator=(const TranspositionsBase& tr) - { return Base::operator=(tr.derived()); } - - #ifndef EIGEN_PARSED_BY_DOXYGEN - /** This is a special case of the templated operator=. Its purpose is to - * prevent a default operator= from hiding the templated operator=. - */ - Map& operator=(const Map& other) - { - m_indices = other.m_indices; - return *this; - } - #endif - - /** const version of indices(). */ - const IndicesType& indices() const { return m_indices; } - /** \returns a reference to the stored array representing the permutation. */ - IndicesType& indices() { return m_indices; } - - protected: - - IndicesType m_indices; -}; - -/** \class PermutationWrapper - * \ingroup Core_Module - * - * \brief Class to view a vector of integers as a permutation matrix - * - * \param _IndicesType the type of the vector of integer (can be any compatible expression) - * - * This class allows to view any vector expression of integers as a permutation matrix. - * - * \sa class PermutationBase, class PermutationMatrix - */ - -struct PermutationStorage {}; - -template class TranspositionsWrapper; -namespace internal { -template -struct traits > -{ - typedef PermutationStorage StorageKind; - typedef typename _IndicesType::Scalar Scalar; - typedef typename _IndicesType::Scalar Index; - typedef _IndicesType IndicesType; - enum { - RowsAtCompileTime = _IndicesType::SizeAtCompileTime, - ColsAtCompileTime = _IndicesType::SizeAtCompileTime, - MaxRowsAtCompileTime = IndicesType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = IndicesType::MaxColsAtCompileTime, - Flags = 0, - CoeffReadCost = _IndicesType::CoeffReadCost - }; -}; -} - -template -class PermutationWrapper : public PermutationBase > -{ - typedef PermutationBase Base; - typedef internal::traits Traits; - public: - - #ifndef EIGEN_PARSED_BY_DOXYGEN - typedef typename Traits::IndicesType IndicesType; - #endif - - inline PermutationWrapper(const IndicesType& a_indices) - : m_indices(a_indices) - {} - - /** const version of indices(). */ - const typename internal::remove_all::type& - indices() const { return m_indices; } - - protected: - - typename IndicesType::Nested m_indices; -}; - -/** \returns the matrix with the permutation applied to the columns. - */ -template -inline const internal::permut_matrix_product_retval -operator*(const MatrixBase& matrix, - const PermutationBase &permutation) -{ - return internal::permut_matrix_product_retval - - (permutation.derived(), matrix.derived()); -} - -/** \returns the matrix with the permutation applied to the rows. - */ -template -inline const internal::permut_matrix_product_retval - -operator*(const PermutationBase &permutation, - const MatrixBase& matrix) -{ - return internal::permut_matrix_product_retval - - (permutation.derived(), matrix.derived()); -} - -namespace internal { - -template -struct traits > -{ - typedef typename MatrixType::PlainObject ReturnType; -}; - -template -struct permut_matrix_product_retval - : public ReturnByValue > -{ - typedef typename remove_all::type MatrixTypeNestedCleaned; - typedef typename MatrixType::Index Index; - - permut_matrix_product_retval(const PermutationType& perm, const MatrixType& matrix) - : m_permutation(perm), m_matrix(matrix) - {} - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - - template inline void evalTo(Dest& dst) const - { - const Index n = Side==OnTheLeft ? rows() : cols(); - // FIXME we need an is_same for expression that is not sensitive to constness. For instance - // is_same_xpr, Block >::value should be true. - if( is_same::value - && blas_traits::HasUsableDirectAccess - && blas_traits::HasUsableDirectAccess - && extract_data(dst) == extract_data(m_matrix)) - { - // apply the permutation inplace - Matrix mask(m_permutation.size()); - mask.fill(false); - Index r = 0; - while(r < m_permutation.size()) - { - // search for the next seed - while(r=m_permutation.size()) - break; - // we got one, let's follow it until we are back to the seed - Index k0 = r++; - Index kPrev = k0; - mask.coeffRef(k0) = true; - for(Index k=m_permutation.indices().coeff(k0); k!=k0; k=m_permutation.indices().coeff(k)) - { - Block(dst, k) - .swap(Block - (dst,((Side==OnTheLeft) ^ Transposed) ? k0 : kPrev)); - - mask.coeffRef(k) = true; - kPrev = k; - } - } - } - else - { - for(int i = 0; i < n; ++i) - { - Block - (dst, ((Side==OnTheLeft) ^ Transposed) ? m_permutation.indices().coeff(i) : i) - - = - - Block - (m_matrix, ((Side==OnTheRight) ^ Transposed) ? m_permutation.indices().coeff(i) : i); - } - } - } - - protected: - const PermutationType& m_permutation; - typename MatrixType::Nested m_matrix; -}; - -/* Template partial specialization for transposed/inverse permutations */ - -template -struct traits > > - : traits -{}; - -} // end namespace internal - -template -class Transpose > - : public EigenBase > > -{ - typedef Derived PermutationType; - typedef typename PermutationType::IndicesType IndicesType; - typedef typename PermutationType::PlainPermutationType PlainPermutationType; - public: - - #ifndef EIGEN_PARSED_BY_DOXYGEN - typedef internal::traits Traits; - typedef typename Derived::DenseMatrixType DenseMatrixType; - enum { - Flags = Traits::Flags, - CoeffReadCost = Traits::CoeffReadCost, - RowsAtCompileTime = Traits::RowsAtCompileTime, - ColsAtCompileTime = Traits::ColsAtCompileTime, - MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime, - MaxColsAtCompileTime = Traits::MaxColsAtCompileTime - }; - typedef typename Traits::Scalar Scalar; - #endif - - Transpose(const PermutationType& p) : m_permutation(p) {} - - inline int rows() const { return m_permutation.rows(); } - inline int cols() const { return m_permutation.cols(); } - - #ifndef EIGEN_PARSED_BY_DOXYGEN - template - void evalTo(MatrixBase& other) const - { - other.setZero(); - for (int i=0; i friend - inline const internal::permut_matrix_product_retval - operator*(const MatrixBase& matrix, const Transpose& trPerm) - { - return internal::permut_matrix_product_retval(trPerm.m_permutation, matrix.derived()); - } - - /** \returns the matrix with the inverse permutation applied to the rows. - */ - template - inline const internal::permut_matrix_product_retval - operator*(const MatrixBase& matrix) const - { - return internal::permut_matrix_product_retval(m_permutation, matrix.derived()); - } - - const PermutationType& nestedPermutation() const { return m_permutation; } - - protected: - const PermutationType& m_permutation; -}; - -template -const PermutationWrapper MatrixBase::asPermutation() const -{ - return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_PERMUTATIONMATRIX_H diff --git a/splinter/src/Core/PlainObjectBase.h b/splinter/src/Core/PlainObjectBase.h deleted file mode 100644 index a4e4af4a7b..0000000000 --- a/splinter/src/Core/PlainObjectBase.h +++ /dev/null @@ -1,822 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_DENSESTORAGEBASE_H -#define EIGEN_DENSESTORAGEBASE_H - -#if defined(EIGEN_INITIALIZE_MATRICES_BY_ZERO) -# define EIGEN_INITIALIZE_COEFFS -# define EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED for(int i=0;i::quiet_NaN(); -#else -# undef EIGEN_INITIALIZE_COEFFS -# define EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED -#endif - -namespace Eigen { - -namespace internal { - -template struct check_rows_cols_for_overflow { - template - static EIGEN_ALWAYS_INLINE void run(Index, Index) - { - } -}; - -template<> struct check_rows_cols_for_overflow { - template - static EIGEN_ALWAYS_INLINE void run(Index rows, Index cols) - { - // http://hg.mozilla.org/mozilla-central/file/6c8a909977d3/xpcom/ds/CheckedInt.h#l242 - // we assume Index is signed - Index max_index = (size_t(1) << (8 * sizeof(Index) - 1)) - 1; // assume Index is signed - bool error = (rows == 0 || cols == 0) ? false - : (rows > max_index / cols); - if (error) - throw_std_bad_alloc(); - } -}; - -template -struct conservative_resize_like_impl; - -template struct matrix_swap_impl; - -} // end namespace internal - -/** \class PlainObjectBase - * \brief %Dense storage base class for matrices and arrays. - * - * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_PLAINOBJECTBASE_PLUGIN. - * - * \sa \ref TopicClassHierarchy - */ -#ifdef EIGEN_PARSED_BY_DOXYGEN -namespace internal { - -// this is a warkaround to doxygen not being able to understand the inheritence logic -// when it is hidden by the dense_xpr_base helper struct. -template struct dense_xpr_base_dispatcher_for_doxygen;// : public MatrixBase {}; -/** This class is just a workaround for Doxygen and it does not not actually exist. */ -template -struct dense_xpr_base_dispatcher_for_doxygen > - : public MatrixBase > {}; -/** This class is just a workaround for Doxygen and it does not not actually exist. */ -template -struct dense_xpr_base_dispatcher_for_doxygen > - : public ArrayBase > {}; - -} // namespace internal - -template -class PlainObjectBase : public internal::dense_xpr_base_dispatcher_for_doxygen -#else -template -class PlainObjectBase : public internal::dense_xpr_base::type -#endif -{ - public: - enum { Options = internal::traits::Options }; - typedef typename internal::dense_xpr_base::type Base; - - typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; - typedef typename internal::traits::Scalar Scalar; - typedef typename internal::packet_traits::type PacketScalar; - typedef typename NumTraits::Real RealScalar; - typedef Derived DenseType; - - using Base::RowsAtCompileTime; - using Base::ColsAtCompileTime; - using Base::SizeAtCompileTime; - using Base::MaxRowsAtCompileTime; - using Base::MaxColsAtCompileTime; - using Base::MaxSizeAtCompileTime; - using Base::IsVectorAtCompileTime; - using Base::Flags; - - template friend class Eigen::Map; - friend class Eigen::Map; - typedef Eigen::Map MapType; - friend class Eigen::Map; - typedef const Eigen::Map ConstMapType; - friend class Eigen::Map; - typedef Eigen::Map AlignedMapType; - friend class Eigen::Map; - typedef const Eigen::Map ConstAlignedMapType; - template struct StridedMapType { typedef Eigen::Map type; }; - template struct StridedConstMapType { typedef Eigen::Map type; }; - template struct StridedAlignedMapType { typedef Eigen::Map type; }; - template struct StridedConstAlignedMapType { typedef Eigen::Map type; }; - - protected: - DenseStorage m_storage; - - public: - enum { NeedsToAlign = SizeAtCompileTime != Dynamic && (internal::traits::Flags & AlignedBit) != 0 }; - EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) - - Base& base() { return *static_cast(this); } - const Base& base() const { return *static_cast(this); } - - EIGEN_STRONG_INLINE Index rows() const { return m_storage.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return m_storage.cols(); } - - EIGEN_STRONG_INLINE const Scalar& coeff(Index rowId, Index colId) const - { - if(Flags & RowMajorBit) - return m_storage.data()[colId + rowId * m_storage.cols()]; - else // column-major - return m_storage.data()[rowId + colId * m_storage.rows()]; - } - - EIGEN_STRONG_INLINE const Scalar& coeff(Index index) const - { - return m_storage.data()[index]; - } - - EIGEN_STRONG_INLINE Scalar& coeffRef(Index rowId, Index colId) - { - if(Flags & RowMajorBit) - return m_storage.data()[colId + rowId * m_storage.cols()]; - else // column-major - return m_storage.data()[rowId + colId * m_storage.rows()]; - } - - EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) - { - return m_storage.data()[index]; - } - - EIGEN_STRONG_INLINE const Scalar& coeffRef(Index rowId, Index colId) const - { - if(Flags & RowMajorBit) - return m_storage.data()[colId + rowId * m_storage.cols()]; - else // column-major - return m_storage.data()[rowId + colId * m_storage.rows()]; - } - - EIGEN_STRONG_INLINE const Scalar& coeffRef(Index index) const - { - return m_storage.data()[index]; - } - - /** \internal */ - template - EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const - { - return internal::ploadt - (m_storage.data() + (Flags & RowMajorBit - ? colId + rowId * m_storage.cols() - : rowId + colId * m_storage.rows())); - } - - /** \internal */ - template - EIGEN_STRONG_INLINE PacketScalar packet(Index index) const - { - return internal::ploadt(m_storage.data() + index); - } - - /** \internal */ - template - EIGEN_STRONG_INLINE void writePacket(Index rowId, Index colId, const PacketScalar& val) - { - internal::pstoret - (m_storage.data() + (Flags & RowMajorBit - ? colId + rowId * m_storage.cols() - : rowId + colId * m_storage.rows()), val); - } - - /** \internal */ - template - EIGEN_STRONG_INLINE void writePacket(Index index, const PacketScalar& val) - { - internal::pstoret(m_storage.data() + index, val); - } - - /** \returns a const pointer to the data array of this matrix */ - EIGEN_STRONG_INLINE const Scalar *data() const - { return m_storage.data(); } - - /** \returns a pointer to the data array of this matrix */ - EIGEN_STRONG_INLINE Scalar *data() - { return m_storage.data(); } - - /** Resizes \c *this to a \a rows x \a cols matrix. - * - * This method is intended for dynamic-size matrices, although it is legal to call it on any - * matrix as long as fixed dimensions are left unchanged. If you only want to change the number - * of rows and/or of columns, you can use resize(NoChange_t, Index), resize(Index, NoChange_t). - * - * If the current number of coefficients of \c *this exactly matches the - * product \a rows * \a cols, then no memory allocation is performed and - * the current values are left unchanged. In all other cases, including - * shrinking, the data is reallocated and all previous values are lost. - * - * Example: \include Matrix_resize_int_int.cpp - * Output: \verbinclude Matrix_resize_int_int.out - * - * \sa resize(Index) for vectors, resize(NoChange_t, Index), resize(Index, NoChange_t) - */ - EIGEN_STRONG_INLINE void resize(Index nbRows, Index nbCols) - { - eigen_assert( EIGEN_IMPLIES(RowsAtCompileTime!=Dynamic,nbRows==RowsAtCompileTime) - && EIGEN_IMPLIES(ColsAtCompileTime!=Dynamic,nbCols==ColsAtCompileTime) - && EIGEN_IMPLIES(RowsAtCompileTime==Dynamic && MaxRowsAtCompileTime!=Dynamic,nbRows<=MaxRowsAtCompileTime) - && EIGEN_IMPLIES(ColsAtCompileTime==Dynamic && MaxColsAtCompileTime!=Dynamic,nbCols<=MaxColsAtCompileTime) - && nbRows>=0 && nbCols>=0 && "Invalid sizes when resizing a matrix or array."); - internal::check_rows_cols_for_overflow::run(nbRows, nbCols); - #ifdef EIGEN_INITIALIZE_COEFFS - Index size = nbRows*nbCols; - bool size_changed = size != this->size(); - m_storage.resize(size, nbRows, nbCols); - if(size_changed) EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED - #else - internal::check_rows_cols_for_overflow::run(nbRows, nbCols); - m_storage.resize(nbRows*nbCols, nbRows, nbCols); - #endif - } - - /** Resizes \c *this to a vector of length \a size - * - * \only_for_vectors. This method does not work for - * partially dynamic matrices when the static dimension is anything other - * than 1. For example it will not work with Matrix. - * - * Example: \include Matrix_resize_int.cpp - * Output: \verbinclude Matrix_resize_int.out - * - * \sa resize(Index,Index), resize(NoChange_t, Index), resize(Index, NoChange_t) - */ - inline void resize(Index size) - { - EIGEN_STATIC_ASSERT_VECTOR_ONLY(PlainObjectBase) - eigen_assert(((SizeAtCompileTime == Dynamic && (MaxSizeAtCompileTime==Dynamic || size<=MaxSizeAtCompileTime)) || SizeAtCompileTime == size) && size>=0); - #ifdef EIGEN_INITIALIZE_COEFFS - bool size_changed = size != this->size(); - #endif - if(RowsAtCompileTime == 1) - m_storage.resize(size, 1, size); - else - m_storage.resize(size, size, 1); - #ifdef EIGEN_INITIALIZE_COEFFS - if(size_changed) EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED - #endif - } - - /** Resizes the matrix, changing only the number of columns. For the parameter of type NoChange_t, just pass the special value \c NoChange - * as in the example below. - * - * Example: \include Matrix_resize_NoChange_int.cpp - * Output: \verbinclude Matrix_resize_NoChange_int.out - * - * \sa resize(Index,Index) - */ - inline void resize(NoChange_t, Index nbCols) - { - resize(rows(), nbCols); - } - - /** Resizes the matrix, changing only the number of rows. For the parameter of type NoChange_t, just pass the special value \c NoChange - * as in the example below. - * - * Example: \include Matrix_resize_int_NoChange.cpp - * Output: \verbinclude Matrix_resize_int_NoChange.out - * - * \sa resize(Index,Index) - */ - inline void resize(Index nbRows, NoChange_t) - { - resize(nbRows, cols()); - } - - /** Resizes \c *this to have the same dimensions as \a other. - * Takes care of doing all the checking that's needed. - * - * Note that copying a row-vector into a vector (and conversely) is allowed. - * The resizing, if any, is then done in the appropriate way so that row-vectors - * remain row-vectors and vectors remain vectors. - */ - template - EIGEN_STRONG_INLINE void resizeLike(const EigenBase& _other) - { - const OtherDerived& other = _other.derived(); - internal::check_rows_cols_for_overflow::run(other.rows(), other.cols()); - const Index othersize = other.rows()*other.cols(); - if(RowsAtCompileTime == 1) - { - eigen_assert(other.rows() == 1 || other.cols() == 1); - resize(1, othersize); - } - else if(ColsAtCompileTime == 1) - { - eigen_assert(other.rows() == 1 || other.cols() == 1); - resize(othersize, 1); - } - else resize(other.rows(), other.cols()); - } - - /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. - * - * The method is intended for matrices of dynamic size. If you only want to change the number - * of rows and/or of columns, you can use conservativeResize(NoChange_t, Index) or - * conservativeResize(Index, NoChange_t). - * - * Matrices are resized relative to the top-left element. In case values need to be - * appended to the matrix they will be uninitialized. - */ - EIGEN_STRONG_INLINE void conservativeResize(Index nbRows, Index nbCols) - { - internal::conservative_resize_like_impl::run(*this, nbRows, nbCols); - } - - /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. - * - * As opposed to conservativeResize(Index rows, Index cols), this version leaves - * the number of columns unchanged. - * - * In case the matrix is growing, new rows will be uninitialized. - */ - EIGEN_STRONG_INLINE void conservativeResize(Index nbRows, NoChange_t) - { - // Note: see the comment in conservativeResize(Index,Index) - conservativeResize(nbRows, cols()); - } - - /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. - * - * As opposed to conservativeResize(Index rows, Index cols), this version leaves - * the number of rows unchanged. - * - * In case the matrix is growing, new columns will be uninitialized. - */ - EIGEN_STRONG_INLINE void conservativeResize(NoChange_t, Index nbCols) - { - // Note: see the comment in conservativeResize(Index,Index) - conservativeResize(rows(), nbCols); - } - - /** Resizes the vector to \a size while retaining old values. - * - * \only_for_vectors. This method does not work for - * partially dynamic matrices when the static dimension is anything other - * than 1. For example it will not work with Matrix. - * - * When values are appended, they will be uninitialized. - */ - EIGEN_STRONG_INLINE void conservativeResize(Index size) - { - internal::conservative_resize_like_impl::run(*this, size); - } - - /** Resizes the matrix to \a rows x \a cols of \c other, while leaving old values untouched. - * - * The method is intended for matrices of dynamic size. If you only want to change the number - * of rows and/or of columns, you can use conservativeResize(NoChange_t, Index) or - * conservativeResize(Index, NoChange_t). - * - * Matrices are resized relative to the top-left element. In case values need to be - * appended to the matrix they will copied from \c other. - */ - template - EIGEN_STRONG_INLINE void conservativeResizeLike(const DenseBase& other) - { - internal::conservative_resize_like_impl::run(*this, other); - } - - /** This is a special case of the templated operator=. Its purpose is to - * prevent a default operator= from hiding the templated operator=. - */ - EIGEN_STRONG_INLINE Derived& operator=(const PlainObjectBase& other) - { - return _set(other); - } - - /** \sa MatrixBase::lazyAssign() */ - template - EIGEN_STRONG_INLINE Derived& lazyAssign(const DenseBase& other) - { - _resize_to_match(other); - return Base::lazyAssign(other.derived()); - } - - template - EIGEN_STRONG_INLINE Derived& operator=(const ReturnByValue& func) - { - resize(func.rows(), func.cols()); - return Base::operator=(func); - } - - EIGEN_STRONG_INLINE PlainObjectBase() : m_storage() - { -// _check_template_params(); -// EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED - } - -#ifndef EIGEN_PARSED_BY_DOXYGEN - // FIXME is it still needed ? - /** \internal */ - PlainObjectBase(internal::constructor_without_unaligned_array_assert) - : m_storage(internal::constructor_without_unaligned_array_assert()) - { -// _check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED - } -#endif - -#ifdef EIGEN_HAVE_RVALUE_REFERENCES - PlainObjectBase(PlainObjectBase&& other) - : m_storage( std::move(other.m_storage) ) - { - } - - PlainObjectBase& operator=(PlainObjectBase&& other) - { - using std::swap; - swap(m_storage, other.m_storage); - return *this; - } -#endif - - /** Copy constructor */ - EIGEN_STRONG_INLINE PlainObjectBase(const PlainObjectBase& other) - : m_storage() - { - _check_template_params(); - lazyAssign(other); - } - - template - EIGEN_STRONG_INLINE PlainObjectBase(const DenseBase &other) - : m_storage() - { - _check_template_params(); - lazyAssign(other); - } - - EIGEN_STRONG_INLINE PlainObjectBase(Index a_size, Index nbRows, Index nbCols) - : m_storage(a_size, nbRows, nbCols) - { -// _check_template_params(); -// EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED - } - - /** \copydoc MatrixBase::operator=(const EigenBase&) - */ - template - EIGEN_STRONG_INLINE Derived& operator=(const EigenBase &other) - { - _resize_to_match(other); - Base::operator=(other.derived()); - return this->derived(); - } - - /** \sa MatrixBase::operator=(const EigenBase&) */ - template - EIGEN_STRONG_INLINE PlainObjectBase(const EigenBase &other) - : m_storage(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols()) - { - _check_template_params(); - internal::check_rows_cols_for_overflow::run(other.derived().rows(), other.derived().cols()); - Base::operator=(other.derived()); - } - - /** \name Map - * These are convenience functions returning Map objects. The Map() static functions return unaligned Map objects, - * while the AlignedMap() functions return aligned Map objects and thus should be called only with 16-byte-aligned - * \a data pointers. - * - * \see class Map - */ - //@{ - static inline ConstMapType Map(const Scalar* data) - { return ConstMapType(data); } - static inline MapType Map(Scalar* data) - { return MapType(data); } - static inline ConstMapType Map(const Scalar* data, Index size) - { return ConstMapType(data, size); } - static inline MapType Map(Scalar* data, Index size) - { return MapType(data, size); } - static inline ConstMapType Map(const Scalar* data, Index rows, Index cols) - { return ConstMapType(data, rows, cols); } - static inline MapType Map(Scalar* data, Index rows, Index cols) - { return MapType(data, rows, cols); } - - static inline ConstAlignedMapType MapAligned(const Scalar* data) - { return ConstAlignedMapType(data); } - static inline AlignedMapType MapAligned(Scalar* data) - { return AlignedMapType(data); } - static inline ConstAlignedMapType MapAligned(const Scalar* data, Index size) - { return ConstAlignedMapType(data, size); } - static inline AlignedMapType MapAligned(Scalar* data, Index size) - { return AlignedMapType(data, size); } - static inline ConstAlignedMapType MapAligned(const Scalar* data, Index rows, Index cols) - { return ConstAlignedMapType(data, rows, cols); } - static inline AlignedMapType MapAligned(Scalar* data, Index rows, Index cols) - { return AlignedMapType(data, rows, cols); } - - template - static inline typename StridedConstMapType >::type Map(const Scalar* data, const Stride& stride) - { return typename StridedConstMapType >::type(data, stride); } - template - static inline typename StridedMapType >::type Map(Scalar* data, const Stride& stride) - { return typename StridedMapType >::type(data, stride); } - template - static inline typename StridedConstMapType >::type Map(const Scalar* data, Index size, const Stride& stride) - { return typename StridedConstMapType >::type(data, size, stride); } - template - static inline typename StridedMapType >::type Map(Scalar* data, Index size, const Stride& stride) - { return typename StridedMapType >::type(data, size, stride); } - template - static inline typename StridedConstMapType >::type Map(const Scalar* data, Index rows, Index cols, const Stride& stride) - { return typename StridedConstMapType >::type(data, rows, cols, stride); } - template - static inline typename StridedMapType >::type Map(Scalar* data, Index rows, Index cols, const Stride& stride) - { return typename StridedMapType >::type(data, rows, cols, stride); } - - template - static inline typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, const Stride& stride) - { return typename StridedConstAlignedMapType >::type(data, stride); } - template - static inline typename StridedAlignedMapType >::type MapAligned(Scalar* data, const Stride& stride) - { return typename StridedAlignedMapType >::type(data, stride); } - template - static inline typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, Index size, const Stride& stride) - { return typename StridedConstAlignedMapType >::type(data, size, stride); } - template - static inline typename StridedAlignedMapType >::type MapAligned(Scalar* data, Index size, const Stride& stride) - { return typename StridedAlignedMapType >::type(data, size, stride); } - template - static inline typename StridedConstAlignedMapType >::type MapAligned(const Scalar* data, Index rows, Index cols, const Stride& stride) - { return typename StridedConstAlignedMapType >::type(data, rows, cols, stride); } - template - static inline typename StridedAlignedMapType >::type MapAligned(Scalar* data, Index rows, Index cols, const Stride& stride) - { return typename StridedAlignedMapType >::type(data, rows, cols, stride); } - //@} - - using Base::setConstant; - Derived& setConstant(Index size, const Scalar& value); - Derived& setConstant(Index rows, Index cols, const Scalar& value); - - using Base::setZero; - Derived& setZero(Index size); - Derived& setZero(Index rows, Index cols); - - using Base::setOnes; - Derived& setOnes(Index size); - Derived& setOnes(Index rows, Index cols); - - using Base::setRandom; - Derived& setRandom(Index size); - Derived& setRandom(Index rows, Index cols); - - #ifdef EIGEN_PLAINOBJECTBASE_PLUGIN - #include EIGEN_PLAINOBJECTBASE_PLUGIN - #endif - - protected: - /** \internal Resizes *this in preparation for assigning \a other to it. - * Takes care of doing all the checking that's needed. - * - * Note that copying a row-vector into a vector (and conversely) is allowed. - * The resizing, if any, is then done in the appropriate way so that row-vectors - * remain row-vectors and vectors remain vectors. - */ - template - EIGEN_STRONG_INLINE void _resize_to_match(const EigenBase& other) - { - #ifdef EIGEN_NO_AUTOMATIC_RESIZING - eigen_assert((this->size()==0 || (IsVectorAtCompileTime ? (this->size() == other.size()) - : (rows() == other.rows() && cols() == other.cols()))) - && "Size mismatch. Automatic resizing is disabled because EIGEN_NO_AUTOMATIC_RESIZING is defined"); - EIGEN_ONLY_USED_FOR_DEBUG(other); - if(this->size()==0) - resizeLike(other); - #else - resizeLike(other); - #endif - } - - /** - * \brief Copies the value of the expression \a other into \c *this with automatic resizing. - * - * *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized), - * it will be initialized. - * - * Note that copying a row-vector into a vector (and conversely) is allowed. - * The resizing, if any, is then done in the appropriate way so that row-vectors - * remain row-vectors and vectors remain vectors. - * - * \sa operator=(const MatrixBase&), _set_noalias() - * - * \internal - */ - template - EIGEN_STRONG_INLINE Derived& _set(const DenseBase& other) - { - _set_selector(other.derived(), typename internal::conditional(int(OtherDerived::Flags) & EvalBeforeAssigningBit), internal::true_type, internal::false_type>::type()); - return this->derived(); - } - - template - EIGEN_STRONG_INLINE void _set_selector(const OtherDerived& other, const internal::true_type&) { _set_noalias(other.eval()); } - - template - EIGEN_STRONG_INLINE void _set_selector(const OtherDerived& other, const internal::false_type&) { _set_noalias(other); } - - /** \internal Like _set() but additionally makes the assumption that no aliasing effect can happen (which - * is the case when creating a new matrix) so one can enforce lazy evaluation. - * - * \sa operator=(const MatrixBase&), _set() - */ - template - EIGEN_STRONG_INLINE Derived& _set_noalias(const DenseBase& other) - { - // I don't think we need this resize call since the lazyAssign will anyways resize - // and lazyAssign will be called by the assign selector. - //_resize_to_match(other); - // the 'false' below means to enforce lazy evaluation. We don't use lazyAssign() because - // it wouldn't allow to copy a row-vector into a column-vector. - return internal::assign_selector::run(this->derived(), other.derived()); - } - - template - EIGEN_STRONG_INLINE void _init2(Index nbRows, Index nbCols, typename internal::enable_if::type* = 0) - { - EIGEN_STATIC_ASSERT(bool(NumTraits::IsInteger) && - bool(NumTraits::IsInteger), - FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED) - resize(nbRows,nbCols); - } - template - EIGEN_STRONG_INLINE void _init2(const Scalar& val0, const Scalar& val1, typename internal::enable_if::type* = 0) - { - EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 2) - m_storage.data()[0] = val0; - m_storage.data()[1] = val1; - } - - template - friend struct internal::matrix_swap_impl; - - /** \internal generic implementation of swap for dense storage since for dynamic-sized matrices of same type it is enough to swap the - * data pointers. - */ - template - void _swap(DenseBase const & other) - { - enum { SwapPointers = internal::is_same::value && Base::SizeAtCompileTime==Dynamic }; - internal::matrix_swap_impl::run(this->derived(), other.const_cast_derived()); - } - - public: -#ifndef EIGEN_PARSED_BY_DOXYGEN - static EIGEN_STRONG_INLINE void _check_template_params() - { - EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, (Options&RowMajor)==RowMajor) - && EIGEN_IMPLIES(MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1, (Options&RowMajor)==0) - && ((RowsAtCompileTime == Dynamic) || (RowsAtCompileTime >= 0)) - && ((ColsAtCompileTime == Dynamic) || (ColsAtCompileTime >= 0)) - && ((MaxRowsAtCompileTime == Dynamic) || (MaxRowsAtCompileTime >= 0)) - && ((MaxColsAtCompileTime == Dynamic) || (MaxColsAtCompileTime >= 0)) - && (MaxRowsAtCompileTime == RowsAtCompileTime || RowsAtCompileTime==Dynamic) - && (MaxColsAtCompileTime == ColsAtCompileTime || ColsAtCompileTime==Dynamic) - && (Options & (DontAlign|RowMajor)) == Options), - INVALID_MATRIX_TEMPLATE_PARAMETERS) - } -#endif - -private: - enum { ThisConstantIsPrivateInPlainObjectBase }; -}; - -namespace internal { - -template -struct conservative_resize_like_impl -{ - typedef typename Derived::Index Index; - static void run(DenseBase& _this, Index rows, Index cols) - { - if (_this.rows() == rows && _this.cols() == cols) return; - EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Derived) - - if ( ( Derived::IsRowMajor && _this.cols() == cols) || // row-major and we change only the number of rows - (!Derived::IsRowMajor && _this.rows() == rows) ) // column-major and we change only the number of columns - { - internal::check_rows_cols_for_overflow::run(rows, cols); - _this.derived().m_storage.conservativeResize(rows*cols,rows,cols); - } - else - { - // The storage order does not allow us to use reallocation. - typename Derived::PlainObject tmp(rows,cols); - const Index common_rows = (std::min)(rows, _this.rows()); - const Index common_cols = (std::min)(cols, _this.cols()); - tmp.block(0,0,common_rows,common_cols) = _this.block(0,0,common_rows,common_cols); - _this.derived().swap(tmp); - } - } - - static void run(DenseBase& _this, const DenseBase& other) - { - if (_this.rows() == other.rows() && _this.cols() == other.cols()) return; - - // Note: Here is space for improvement. Basically, for conservativeResize(Index,Index), - // neither RowsAtCompileTime or ColsAtCompileTime must be Dynamic. If only one of the - // dimensions is dynamic, one could use either conservativeResize(Index rows, NoChange_t) or - // conservativeResize(NoChange_t, Index cols). For these methods new static asserts like - // EIGEN_STATIC_ASSERT_DYNAMIC_ROWS and EIGEN_STATIC_ASSERT_DYNAMIC_COLS would be good. - EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(Derived) - EIGEN_STATIC_ASSERT_DYNAMIC_SIZE(OtherDerived) - - if ( ( Derived::IsRowMajor && _this.cols() == other.cols()) || // row-major and we change only the number of rows - (!Derived::IsRowMajor && _this.rows() == other.rows()) ) // column-major and we change only the number of columns - { - const Index new_rows = other.rows() - _this.rows(); - const Index new_cols = other.cols() - _this.cols(); - _this.derived().m_storage.conservativeResize(other.size(),other.rows(),other.cols()); - if (new_rows>0) - _this.bottomRightCorner(new_rows, other.cols()) = other.bottomRows(new_rows); - else if (new_cols>0) - _this.bottomRightCorner(other.rows(), new_cols) = other.rightCols(new_cols); - } - else - { - // The storage order does not allow us to use reallocation. - typename Derived::PlainObject tmp(other); - const Index common_rows = (std::min)(tmp.rows(), _this.rows()); - const Index common_cols = (std::min)(tmp.cols(), _this.cols()); - tmp.block(0,0,common_rows,common_cols) = _this.block(0,0,common_rows,common_cols); - _this.derived().swap(tmp); - } - } -}; - -// Here, the specialization for vectors inherits from the general matrix case -// to allow calling .conservativeResize(rows,cols) on vectors. -template -struct conservative_resize_like_impl - : conservative_resize_like_impl -{ - using conservative_resize_like_impl::run; - - typedef typename Derived::Index Index; - static void run(DenseBase& _this, Index size) - { - const Index new_rows = Derived::RowsAtCompileTime==1 ? 1 : size; - const Index new_cols = Derived::RowsAtCompileTime==1 ? size : 1; - _this.derived().m_storage.conservativeResize(size,new_rows,new_cols); - } - - static void run(DenseBase& _this, const DenseBase& other) - { - if (_this.rows() == other.rows() && _this.cols() == other.cols()) return; - - const Index num_new_elements = other.size() - _this.size(); - - const Index new_rows = Derived::RowsAtCompileTime==1 ? 1 : other.rows(); - const Index new_cols = Derived::RowsAtCompileTime==1 ? other.cols() : 1; - _this.derived().m_storage.conservativeResize(other.size(),new_rows,new_cols); - - if (num_new_elements > 0) - _this.tail(num_new_elements) = other.tail(num_new_elements); - } -}; - -template -struct matrix_swap_impl -{ - static inline void run(MatrixTypeA& a, MatrixTypeB& b) - { - a.base().swap(b); - } -}; - -template -struct matrix_swap_impl -{ - static inline void run(MatrixTypeA& a, MatrixTypeB& b) - { - static_cast(a).m_storage.swap(static_cast(b).m_storage); - } -}; - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_DENSESTORAGEBASE_H diff --git a/splinter/src/Core/ProductBase.h b/splinter/src/Core/ProductBase.h deleted file mode 100644 index cf74470a9a..0000000000 --- a/splinter/src/Core/ProductBase.h +++ /dev/null @@ -1,290 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_PRODUCTBASE_H -#define EIGEN_PRODUCTBASE_H - -namespace Eigen { - -/** \class ProductBase - * \ingroup Core_Module - * - */ - -namespace internal { -template -struct traits > -{ - typedef MatrixXpr XprKind; - typedef typename remove_all<_Lhs>::type Lhs; - typedef typename remove_all<_Rhs>::type Rhs; - typedef typename scalar_product_traits::ReturnType Scalar; - typedef typename promote_storage_type::StorageKind, - typename traits::StorageKind>::ret StorageKind; - typedef typename promote_index_type::Index, - typename traits::Index>::type Index; - enum { - RowsAtCompileTime = traits::RowsAtCompileTime, - ColsAtCompileTime = traits::ColsAtCompileTime, - MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, - MaxColsAtCompileTime = traits::MaxColsAtCompileTime, - Flags = (MaxRowsAtCompileTime==1 ? RowMajorBit : 0) - | EvalBeforeNestingBit | EvalBeforeAssigningBit | NestByRefBit, - // Note that EvalBeforeNestingBit and NestByRefBit - // are not used in practice because nested is overloaded for products - CoeffReadCost = 0 // FIXME why is it needed ? - }; -}; -} - -#define EIGEN_PRODUCT_PUBLIC_INTERFACE(Derived) \ - typedef ProductBase Base; \ - EIGEN_DENSE_PUBLIC_INTERFACE(Derived) \ - typedef typename Base::LhsNested LhsNested; \ - typedef typename Base::_LhsNested _LhsNested; \ - typedef typename Base::LhsBlasTraits LhsBlasTraits; \ - typedef typename Base::ActualLhsType ActualLhsType; \ - typedef typename Base::_ActualLhsType _ActualLhsType; \ - typedef typename Base::RhsNested RhsNested; \ - typedef typename Base::_RhsNested _RhsNested; \ - typedef typename Base::RhsBlasTraits RhsBlasTraits; \ - typedef typename Base::ActualRhsType ActualRhsType; \ - typedef typename Base::_ActualRhsType _ActualRhsType; \ - using Base::m_lhs; \ - using Base::m_rhs; - -template -class ProductBase : public MatrixBase -{ - public: - typedef MatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(ProductBase) - - typedef typename Lhs::Nested LhsNested; - typedef typename internal::remove_all::type _LhsNested; - typedef internal::blas_traits<_LhsNested> LhsBlasTraits; - typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; - typedef typename internal::remove_all::type _ActualLhsType; - typedef typename internal::traits::Scalar LhsScalar; - - typedef typename Rhs::Nested RhsNested; - typedef typename internal::remove_all::type _RhsNested; - typedef internal::blas_traits<_RhsNested> RhsBlasTraits; - typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; - typedef typename internal::remove_all::type _ActualRhsType; - typedef typename internal::traits::Scalar RhsScalar; - - // Diagonal of a product: no need to evaluate the arguments because they are going to be evaluated only once - typedef CoeffBasedProduct FullyLazyCoeffBaseProductType; - - public: - -#ifndef EIGEN_NO_MALLOC - typedef typename Base::PlainObject BasePlainObject; - typedef Matrix DynPlainObject; - typedef typename internal::conditional<(BasePlainObject::SizeAtCompileTime==Dynamic) || (BasePlainObject::SizeAtCompileTime*int(sizeof(Scalar)) < int(EIGEN_STACK_ALLOCATION_LIMIT)), - BasePlainObject, DynPlainObject>::type PlainObject; -#else - typedef typename Base::PlainObject PlainObject; -#endif - - ProductBase(const Lhs& a_lhs, const Rhs& a_rhs) - : m_lhs(a_lhs), m_rhs(a_rhs) - { - eigen_assert(a_lhs.cols() == a_rhs.rows() - && "invalid matrix product" - && "if you wanted a coeff-wise or a dot product use the respective explicit functions"); - } - - inline Index rows() const { return m_lhs.rows(); } - inline Index cols() const { return m_rhs.cols(); } - - template - inline void evalTo(Dest& dst) const { dst.setZero(); scaleAndAddTo(dst,Scalar(1)); } - - template - inline void addTo(Dest& dst) const { scaleAndAddTo(dst,Scalar(1)); } - - template - inline void subTo(Dest& dst) const { scaleAndAddTo(dst,Scalar(-1)); } - - template - inline void scaleAndAddTo(Dest& dst, const Scalar& alpha) const { derived().scaleAndAddTo(dst,alpha); } - - const _LhsNested& lhs() const { return m_lhs; } - const _RhsNested& rhs() const { return m_rhs; } - - // Implicit conversion to the nested type (trigger the evaluation of the product) - operator const PlainObject& () const - { - m_result.resize(m_lhs.rows(), m_rhs.cols()); - derived().evalTo(m_result); - return m_result; - } - - const Diagonal diagonal() const - { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs); } - - template - const Diagonal diagonal() const - { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs); } - - const Diagonal diagonal(Index index) const - { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs).diagonal(index); } - - // restrict coeff accessors to 1x1 expressions. No need to care about mutators here since this isnt a Lvalue expression - typename Base::CoeffReturnType coeff(Index row, Index col) const - { -#ifdef EIGEN2_SUPPORT - return lhs().row(row).cwiseProduct(rhs().col(col).transpose()).sum(); -#else - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - Matrix result = *this; - return result.coeff(row,col); -#endif - } - - typename Base::CoeffReturnType coeff(Index i) const - { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - Matrix result = *this; - return result.coeff(i); - } - - const Scalar& coeffRef(Index row, Index col) const - { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - return derived().coeffRef(row,col); - } - - const Scalar& coeffRef(Index i) const - { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - return derived().coeffRef(i); - } - - protected: - - LhsNested m_lhs; - RhsNested m_rhs; - - mutable PlainObject m_result; -}; - -// here we need to overload the nested rule for products -// such that the nested type is a const reference to a plain matrix -namespace internal { -template -struct nested, N, PlainObject> -{ - typedef typename GeneralProduct::PlainObject const& type; -}; -template -struct nested, N, PlainObject> -{ - typedef typename GeneralProduct::PlainObject const& type; -}; -} - -template -class ScaledProduct; - -// Note that these two operator* functions are not defined as member -// functions of ProductBase, because, otherwise we would have to -// define all overloads defined in MatrixBase. Furthermore, Using -// "using Base::operator*" would not work with MSVC. -// -// Also note that here we accept any compatible scalar types -template -const ScaledProduct -operator*(const ProductBase& prod, const typename Derived::Scalar& x) -{ return ScaledProduct(prod.derived(), x); } - -template -typename internal::enable_if::value, - const ScaledProduct >::type -operator*(const ProductBase& prod, const typename Derived::RealScalar& x) -{ return ScaledProduct(prod.derived(), x); } - - -template -const ScaledProduct -operator*(const typename Derived::Scalar& x,const ProductBase& prod) -{ return ScaledProduct(prod.derived(), x); } - -template -typename internal::enable_if::value, - const ScaledProduct >::type -operator*(const typename Derived::RealScalar& x,const ProductBase& prod) -{ return ScaledProduct(prod.derived(), x); } - -namespace internal { -template -struct traits > - : traits, - typename NestedProduct::_LhsNested, - typename NestedProduct::_RhsNested> > -{ - typedef typename traits::StorageKind StorageKind; -}; -} - -template -class ScaledProduct - : public ProductBase, - typename NestedProduct::_LhsNested, - typename NestedProduct::_RhsNested> -{ - public: - typedef ProductBase, - typename NestedProduct::_LhsNested, - typename NestedProduct::_RhsNested> Base; - typedef typename Base::Scalar Scalar; - typedef typename Base::PlainObject PlainObject; -// EIGEN_PRODUCT_PUBLIC_INTERFACE(ScaledProduct) - - ScaledProduct(const NestedProduct& prod, const Scalar& x) - : Base(prod.lhs(),prod.rhs()), m_prod(prod), m_alpha(x) {} - - template - inline void evalTo(Dest& dst) const { dst.setZero(); scaleAndAddTo(dst, Scalar(1)); } - - template - inline void addTo(Dest& dst) const { scaleAndAddTo(dst, Scalar(1)); } - - template - inline void subTo(Dest& dst) const { scaleAndAddTo(dst, Scalar(-1)); } - - template - inline void scaleAndAddTo(Dest& dst, const Scalar& a_alpha) const { m_prod.derived().scaleAndAddTo(dst,a_alpha * m_alpha); } - - const Scalar& alpha() const { return m_alpha; } - - protected: - const NestedProduct& m_prod; - Scalar m_alpha; -}; - -/** \internal - * Overloaded to perform an efficient C = (A*B).lazy() */ -template -template -Derived& MatrixBase::lazyAssign(const ProductBase& other) -{ - other.derived().evalTo(derived()); - return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_PRODUCTBASE_H diff --git a/splinter/src/Core/Random.h b/splinter/src/Core/Random.h deleted file mode 100644 index 480fea408d..0000000000 --- a/splinter/src/Core/Random.h +++ /dev/null @@ -1,152 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_RANDOM_H -#define EIGEN_RANDOM_H - -namespace Eigen { - -namespace internal { - -template struct scalar_random_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_random_op) - template - inline const Scalar operator() (Index, Index = 0) const { return random(); } -}; - -template -struct functor_traits > -{ enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false, IsRepeatable = false }; }; - -} // end namespace internal - -/** \returns a random matrix expression - * - * The parameters \a rows and \a cols are the number of rows and of columns of - * the returned matrix. Must be compatible with this MatrixBase type. - * - * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, - * it is redundant to pass \a rows and \a cols as arguments, so Random() should be used - * instead. - * - * Example: \include MatrixBase_random_int_int.cpp - * Output: \verbinclude MatrixBase_random_int_int.out - * - * This expression has the "evaluate before nesting" flag so that it will be evaluated into - * a temporary matrix whenever it is nested in a larger expression. This prevents unexpected - * behavior with expressions involving random matrices. - * - * \sa MatrixBase::setRandom(), MatrixBase::Random(Index), MatrixBase::Random() - */ -template -inline const CwiseNullaryOp::Scalar>, Derived> -DenseBase::Random(Index rows, Index cols) -{ - return NullaryExpr(rows, cols, internal::scalar_random_op()); -} - -/** \returns a random vector expression - * - * The parameter \a size is the size of the returned vector. - * Must be compatible with this MatrixBase type. - * - * \only_for_vectors - * - * This variant is meant to be used for dynamic-size vector types. For fixed-size types, - * it is redundant to pass \a size as argument, so Random() should be used - * instead. - * - * Example: \include MatrixBase_random_int.cpp - * Output: \verbinclude MatrixBase_random_int.out - * - * This expression has the "evaluate before nesting" flag so that it will be evaluated into - * a temporary vector whenever it is nested in a larger expression. This prevents unexpected - * behavior with expressions involving random matrices. - * - * \sa MatrixBase::setRandom(), MatrixBase::Random(Index,Index), MatrixBase::Random() - */ -template -inline const CwiseNullaryOp::Scalar>, Derived> -DenseBase::Random(Index size) -{ - return NullaryExpr(size, internal::scalar_random_op()); -} - -/** \returns a fixed-size random matrix or vector expression - * - * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you - * need to use the variants taking size arguments. - * - * Example: \include MatrixBase_random.cpp - * Output: \verbinclude MatrixBase_random.out - * - * This expression has the "evaluate before nesting" flag so that it will be evaluated into - * a temporary matrix whenever it is nested in a larger expression. This prevents unexpected - * behavior with expressions involving random matrices. - * - * \sa MatrixBase::setRandom(), MatrixBase::Random(Index,Index), MatrixBase::Random(Index) - */ -template -inline const CwiseNullaryOp::Scalar>, Derived> -DenseBase::Random() -{ - return NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_random_op()); -} - -/** Sets all coefficients in this expression to random values. - * - * Example: \include MatrixBase_setRandom.cpp - * Output: \verbinclude MatrixBase_setRandom.out - * - * \sa class CwiseNullaryOp, setRandom(Index), setRandom(Index,Index) - */ -template -inline Derived& DenseBase::setRandom() -{ - return *this = Random(rows(), cols()); -} - -/** Resizes to the given \a newSize, and sets all coefficients in this expression to random values. - * - * \only_for_vectors - * - * Example: \include Matrix_setRandom_int.cpp - * Output: \verbinclude Matrix_setRandom_int.out - * - * \sa MatrixBase::setRandom(), setRandom(Index,Index), class CwiseNullaryOp, MatrixBase::Random() - */ -template -EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setRandom(Index newSize) -{ - resize(newSize); - return setRandom(); -} - -/** Resizes to the given size, and sets all coefficients in this expression to random values. - * - * \param nbRows the new number of rows - * \param nbCols the new number of columns - * - * Example: \include Matrix_setRandom_int_int.cpp - * Output: \verbinclude Matrix_setRandom_int_int.out - * - * \sa MatrixBase::setRandom(), setRandom(Index), class CwiseNullaryOp, MatrixBase::Random() - */ -template -EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setRandom(Index nbRows, Index nbCols) -{ - resize(nbRows, nbCols); - return setRandom(); -} - -} // end namespace Eigen - -#endif // EIGEN_RANDOM_H diff --git a/splinter/src/Core/Redux.h b/splinter/src/Core/Redux.h deleted file mode 100644 index 9b8662a6f9..0000000000 --- a/splinter/src/Core/Redux.h +++ /dev/null @@ -1,409 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_REDUX_H -#define EIGEN_REDUX_H - -namespace Eigen { - -namespace internal { - -// TODO -// * implement other kind of vectorization -// * factorize code - -/*************************************************************************** -* Part 1 : the logic deciding a strategy for vectorization and unrolling -***************************************************************************/ - -template -struct redux_traits -{ -public: - enum { - PacketSize = packet_traits::size, - InnerMaxSize = int(Derived::IsRowMajor) - ? Derived::MaxColsAtCompileTime - : Derived::MaxRowsAtCompileTime - }; - - enum { - MightVectorize = (int(Derived::Flags)&ActualPacketAccessBit) - && (functor_traits::PacketAccess), - MayLinearVectorize = MightVectorize && (int(Derived::Flags)&LinearAccessBit), - MaySliceVectorize = MightVectorize && int(InnerMaxSize)>=3*PacketSize - }; - -public: - enum { - Traversal = int(MayLinearVectorize) ? int(LinearVectorizedTraversal) - : int(MaySliceVectorize) ? int(SliceVectorizedTraversal) - : int(DefaultTraversal) - }; - -public: - enum { - Cost = ( Derived::SizeAtCompileTime == Dynamic - || Derived::CoeffReadCost == Dynamic - || (Derived::SizeAtCompileTime!=1 && functor_traits::Cost == Dynamic) - ) ? Dynamic - : Derived::SizeAtCompileTime * Derived::CoeffReadCost - + (Derived::SizeAtCompileTime-1) * functor_traits::Cost, - UnrollingLimit = EIGEN_UNROLLING_LIMIT * (int(Traversal) == int(DefaultTraversal) ? 1 : int(PacketSize)) - }; - -public: - enum { - Unrolling = Cost != Dynamic && Cost <= UnrollingLimit - ? CompleteUnrolling - : NoUnrolling - }; -}; - -/*************************************************************************** -* Part 2 : unrollers -***************************************************************************/ - -/*** no vectorization ***/ - -template -struct redux_novec_unroller -{ - enum { - HalfLength = Length/2 - }; - - typedef typename Derived::Scalar Scalar; - - static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func) - { - return func(redux_novec_unroller::run(mat,func), - redux_novec_unroller::run(mat,func)); - } -}; - -template -struct redux_novec_unroller -{ - enum { - outer = Start / Derived::InnerSizeAtCompileTime, - inner = Start % Derived::InnerSizeAtCompileTime - }; - - typedef typename Derived::Scalar Scalar; - - static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func&) - { - return mat.coeffByOuterInner(outer, inner); - } -}; - -// This is actually dead code and will never be called. It is required -// to prevent false warnings regarding failed inlining though -// for 0 length run() will never be called at all. -template -struct redux_novec_unroller -{ - typedef typename Derived::Scalar Scalar; - static EIGEN_STRONG_INLINE Scalar run(const Derived&, const Func&) { return Scalar(); } -}; - -/*** vectorization ***/ - -template -struct redux_vec_unroller -{ - enum { - PacketSize = packet_traits::size, - HalfLength = Length/2 - }; - - typedef typename Derived::Scalar Scalar; - typedef typename packet_traits::type PacketScalar; - - static EIGEN_STRONG_INLINE PacketScalar run(const Derived &mat, const Func& func) - { - return func.packetOp( - redux_vec_unroller::run(mat,func), - redux_vec_unroller::run(mat,func) ); - } -}; - -template -struct redux_vec_unroller -{ - enum { - index = Start * packet_traits::size, - outer = index / int(Derived::InnerSizeAtCompileTime), - inner = index % int(Derived::InnerSizeAtCompileTime), - alignment = (Derived::Flags & AlignedBit) ? Aligned : Unaligned - }; - - typedef typename Derived::Scalar Scalar; - typedef typename packet_traits::type PacketScalar; - - static EIGEN_STRONG_INLINE PacketScalar run(const Derived &mat, const Func&) - { - return mat.template packetByOuterInner(outer, inner); - } -}; - -/*************************************************************************** -* Part 3 : implementation of all cases -***************************************************************************/ - -template::Traversal, - int Unrolling = redux_traits::Unrolling -> -struct redux_impl; - -template -struct redux_impl -{ - typedef typename Derived::Scalar Scalar; - typedef typename Derived::Index Index; - static EIGEN_STRONG_INLINE Scalar run(const Derived& mat, const Func& func) - { - eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); - Scalar res; - res = mat.coeffByOuterInner(0, 0); - for(Index i = 1; i < mat.innerSize(); ++i) - res = func(res, mat.coeffByOuterInner(0, i)); - for(Index i = 1; i < mat.outerSize(); ++i) - for(Index j = 0; j < mat.innerSize(); ++j) - res = func(res, mat.coeffByOuterInner(i, j)); - return res; - } -}; - -template -struct redux_impl - : public redux_novec_unroller -{}; - -template -struct redux_impl -{ - typedef typename Derived::Scalar Scalar; - typedef typename packet_traits::type PacketScalar; - typedef typename Derived::Index Index; - - static Scalar run(const Derived& mat, const Func& func) - { - const Index size = mat.size(); - eigen_assert(size && "you are using an empty matrix"); - const Index packetSize = packet_traits::size; - const Index alignedStart = internal::first_aligned(mat); - enum { - alignment = bool(Derived::Flags & DirectAccessBit) || bool(Derived::Flags & AlignedBit) - ? Aligned : Unaligned - }; - const Index alignedSize2 = ((size-alignedStart)/(2*packetSize))*(2*packetSize); - const Index alignedSize = ((size-alignedStart)/(packetSize))*(packetSize); - const Index alignedEnd2 = alignedStart + alignedSize2; - const Index alignedEnd = alignedStart + alignedSize; - Scalar res; - if(alignedSize) - { - PacketScalar packet_res0 = mat.template packet(alignedStart); - if(alignedSize>packetSize) // we have at least two packets to partly unroll the loop - { - PacketScalar packet_res1 = mat.template packet(alignedStart+packetSize); - for(Index index = alignedStart + 2*packetSize; index < alignedEnd2; index += 2*packetSize) - { - packet_res0 = func.packetOp(packet_res0, mat.template packet(index)); - packet_res1 = func.packetOp(packet_res1, mat.template packet(index+packetSize)); - } - - packet_res0 = func.packetOp(packet_res0,packet_res1); - if(alignedEnd>alignedEnd2) - packet_res0 = func.packetOp(packet_res0, mat.template packet(alignedEnd2)); - } - res = func.predux(packet_res0); - - for(Index index = 0; index < alignedStart; ++index) - res = func(res,mat.coeff(index)); - - for(Index index = alignedEnd; index < size; ++index) - res = func(res,mat.coeff(index)); - } - else // too small to vectorize anything. - // since this is dynamic-size hence inefficient anyway for such small sizes, don't try to optimize. - { - res = mat.coeff(0); - for(Index index = 1; index < size; ++index) - res = func(res,mat.coeff(index)); - } - - return res; - } -}; - -// NOTE: for SliceVectorizedTraversal we simply bypass unrolling -template -struct redux_impl -{ - typedef typename Derived::Scalar Scalar; - typedef typename packet_traits::type PacketScalar; - typedef typename Derived::Index Index; - - static Scalar run(const Derived& mat, const Func& func) - { - eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); - const Index innerSize = mat.innerSize(); - const Index outerSize = mat.outerSize(); - enum { - packetSize = packet_traits::size - }; - const Index packetedInnerSize = ((innerSize)/packetSize)*packetSize; - Scalar res; - if(packetedInnerSize) - { - PacketScalar packet_res = mat.template packet(0,0); - for(Index j=0; j(j,i)); - - res = func.predux(packet_res); - for(Index j=0; j::run(mat, func); - } - - return res; - } -}; - -template -struct redux_impl -{ - typedef typename Derived::Scalar Scalar; - typedef typename packet_traits::type PacketScalar; - enum { - PacketSize = packet_traits::size, - Size = Derived::SizeAtCompileTime, - VectorizedSize = (Size / PacketSize) * PacketSize - }; - static EIGEN_STRONG_INLINE Scalar run(const Derived& mat, const Func& func) - { - eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); - Scalar res = func.predux(redux_vec_unroller::run(mat,func)); - if (VectorizedSize != Size) - res = func(res,redux_novec_unroller::run(mat,func)); - return res; - } -}; - -} // end namespace internal - -/*************************************************************************** -* Part 4 : public API -***************************************************************************/ - - -/** \returns the result of a full redux operation on the whole matrix or vector using \a func - * - * The template parameter \a BinaryOp is the type of the functor \a func which must be - * an associative operator. Both current STL and TR1 functor styles are handled. - * - * \sa DenseBase::sum(), DenseBase::minCoeff(), DenseBase::maxCoeff(), MatrixBase::colwise(), MatrixBase::rowwise() - */ -template -template -EIGEN_STRONG_INLINE typename internal::result_of::Scalar)>::type -DenseBase::redux(const Func& func) const -{ - typedef typename internal::remove_all::type ThisNested; - return internal::redux_impl - ::run(derived(), func); -} - -/** \returns the minimum of all coefficients of \c *this. - * \warning the result is undefined if \c *this contains NaN. - */ -template -EIGEN_STRONG_INLINE typename internal::traits::Scalar -DenseBase::minCoeff() const -{ - return this->redux(Eigen::internal::scalar_min_op()); -} - -/** \returns the maximum of all coefficients of \c *this. - * \warning the result is undefined if \c *this contains NaN. - */ -template -EIGEN_STRONG_INLINE typename internal::traits::Scalar -DenseBase::maxCoeff() const -{ - return this->redux(Eigen::internal::scalar_max_op()); -} - -/** \returns the sum of all coefficients of *this - * - * \sa trace(), prod(), mean() - */ -template -EIGEN_STRONG_INLINE typename internal::traits::Scalar -DenseBase::sum() const -{ - if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0)) - return Scalar(0); - return this->redux(Eigen::internal::scalar_sum_op()); -} - -/** \returns the mean of all coefficients of *this -* -* \sa trace(), prod(), sum() -*/ -template -EIGEN_STRONG_INLINE typename internal::traits::Scalar -DenseBase::mean() const -{ - return Scalar(this->redux(Eigen::internal::scalar_sum_op())) / Scalar(this->size()); -} - -/** \returns the product of all coefficients of *this - * - * Example: \include MatrixBase_prod.cpp - * Output: \verbinclude MatrixBase_prod.out - * - * \sa sum(), mean(), trace() - */ -template -EIGEN_STRONG_INLINE typename internal::traits::Scalar -DenseBase::prod() const -{ - if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0)) - return Scalar(1); - return this->redux(Eigen::internal::scalar_product_op()); -} - -/** \returns the trace of \c *this, i.e. the sum of the coefficients on the main diagonal. - * - * \c *this can be any matrix, not necessarily square. - * - * \sa diagonal(), sum() - */ -template -EIGEN_STRONG_INLINE typename internal::traits::Scalar -MatrixBase::trace() const -{ - return derived().diagonal().sum(); -} - -} // end namespace Eigen - -#endif // EIGEN_REDUX_H diff --git a/splinter/src/Core/Ref.h b/splinter/src/Core/Ref.h deleted file mode 100644 index 7a3becaf88..0000000000 --- a/splinter/src/Core/Ref.h +++ /dev/null @@ -1,278 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2012 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_REF_H -#define EIGEN_REF_H - -namespace Eigen { - -template class RefBase; -template,OuterStride<> >::type > class Ref; - -/** \class Ref - * \ingroup Core_Module - * - * \brief A matrix or vector expression mapping an existing expressions - * - * \tparam PlainObjectType the equivalent matrix type of the mapped data - * \tparam Options specifies whether the pointer is \c #Aligned, or \c #Unaligned. - * The default is \c #Unaligned. - * \tparam StrideType optionally specifies strides. By default, Ref implies a contiguous storage along the inner dimension (inner stride==1), - * but accept a variable outer stride (leading dimension). - * This can be overridden by specifying strides. - * The type passed here must be a specialization of the Stride template, see examples below. - * - * This class permits to write non template functions taking Eigen's object as parameters while limiting the number of copies. - * A Ref<> object can represent either a const expression or a l-value: - * \code - * // in-out argument: - * void foo1(Ref x); - * - * // read-only const argument: - * void foo2(const Ref& x); - * \endcode - * - * In the in-out case, the input argument must satisfies the constraints of the actual Ref<> type, otherwise a compilation issue will be triggered. - * By default, a Ref can reference any dense vector expression of float having a contiguous memory layout. - * Likewise, a Ref can reference any column major dense matrix expression of float whose column's elements are contiguously stored with - * the possibility to have a constant space inbetween each column, i.e.: the inner stride mmust be equal to 1, but the outer-stride (or leading dimension), - * can be greater than the number of rows. - * - * In the const case, if the input expression does not match the above requirement, then it is evaluated into a temporary before being passed to the function. - * Here are some examples: - * \code - * MatrixXf A; - * VectorXf a; - * foo1(a.head()); // OK - * foo1(A.col()); // OK - * foo1(A.row()); // compilation error because here innerstride!=1 - * foo2(A.row()); // The row is copied into a contiguous temporary - * foo2(2*a); // The expression is evaluated into a temporary - * foo2(A.col().segment(2,4)); // No temporary - * \endcode - * - * The range of inputs that can be referenced without temporary can be enlarged using the last two template parameter. - * Here is an example accepting an innerstride!=1: - * \code - * // in-out argument: - * void foo3(Ref > x); - * foo3(A.row()); // OK - * \endcode - * The downside here is that the function foo3 might be significantly slower than foo1 because it won't be able to exploit vectorization, and will involved more - * expensive address computations even if the input is contiguously stored in memory. To overcome this issue, one might propose to overloads internally calling a - * template function, e.g.: - * \code - * // in the .h: - * void foo(const Ref& A); - * void foo(const Ref >& A); - * - * // in the .cpp: - * template void foo_impl(const TypeOfA& A) { - * ... // crazy code goes here - * } - * void foo(const Ref& A) { foo_impl(A); } - * void foo(const Ref >& A) { foo_impl(A); } - * \endcode - * - * - * \sa PlainObjectBase::Map(), \ref TopicStorageOrders - */ - -namespace internal { - -template -struct traits > - : public traits > -{ - typedef _PlainObjectType PlainObjectType; - typedef _StrideType StrideType; - enum { - Options = _Options, - Flags = traits >::Flags | NestByRefBit - }; - - template struct match { - enum { - HasDirectAccess = internal::has_direct_access::ret, - StorageOrderMatch = PlainObjectType::IsVectorAtCompileTime || Derived::IsVectorAtCompileTime || ((PlainObjectType::Flags&RowMajorBit)==(Derived::Flags&RowMajorBit)), - InnerStrideMatch = int(StrideType::InnerStrideAtCompileTime)==int(Dynamic) - || int(StrideType::InnerStrideAtCompileTime)==int(Derived::InnerStrideAtCompileTime) - || (int(StrideType::InnerStrideAtCompileTime)==0 && int(Derived::InnerStrideAtCompileTime)==1), - OuterStrideMatch = Derived::IsVectorAtCompileTime - || int(StrideType::OuterStrideAtCompileTime)==int(Dynamic) || int(StrideType::OuterStrideAtCompileTime)==int(Derived::OuterStrideAtCompileTime), - AlignmentMatch = (_Options!=Aligned) || ((PlainObjectType::Flags&AlignedBit)==0) || ((traits::Flags&AlignedBit)==AlignedBit), - ScalarTypeMatch = internal::is_same::value, - MatchAtCompileTime = HasDirectAccess && StorageOrderMatch && InnerStrideMatch && OuterStrideMatch && AlignmentMatch && ScalarTypeMatch - }; - typedef typename internal::conditional::type type; - }; - -}; - -template -struct traits > : public traits {}; - -} - -template class RefBase - : public MapBase -{ - typedef typename internal::traits::PlainObjectType PlainObjectType; - typedef typename internal::traits::StrideType StrideType; - -public: - - typedef MapBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(RefBase) - - inline Index innerStride() const - { - return StrideType::InnerStrideAtCompileTime != 0 ? m_stride.inner() : 1; - } - - inline Index outerStride() const - { - return StrideType::OuterStrideAtCompileTime != 0 ? m_stride.outer() - : IsVectorAtCompileTime ? this->size() - : int(Flags)&RowMajorBit ? this->cols() - : this->rows(); - } - - RefBase() - : Base(0,RowsAtCompileTime==Dynamic?0:RowsAtCompileTime,ColsAtCompileTime==Dynamic?0:ColsAtCompileTime), - // Stride<> does not allow default ctor for Dynamic strides, so let' initialize it with dummy values: - m_stride(StrideType::OuterStrideAtCompileTime==Dynamic?0:StrideType::OuterStrideAtCompileTime, - StrideType::InnerStrideAtCompileTime==Dynamic?0:StrideType::InnerStrideAtCompileTime) - {} - - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(RefBase) - -protected: - - typedef Stride StrideBase; - - template - void construct(Expression& expr) - { - if(PlainObjectType::RowsAtCompileTime==1) - { - eigen_assert(expr.rows()==1 || expr.cols()==1); - ::new (static_cast(this)) Base(expr.data(), 1, expr.size()); - } - else if(PlainObjectType::ColsAtCompileTime==1) - { - eigen_assert(expr.rows()==1 || expr.cols()==1); - ::new (static_cast(this)) Base(expr.data(), expr.size(), 1); - } - else - ::new (static_cast(this)) Base(expr.data(), expr.rows(), expr.cols()); - - if(Expression::IsVectorAtCompileTime && (!PlainObjectType::IsVectorAtCompileTime) && ((Expression::Flags&RowMajorBit)!=(PlainObjectType::Flags&RowMajorBit))) - ::new (&m_stride) StrideBase(expr.innerStride(), StrideType::InnerStrideAtCompileTime==0?0:1); - else - ::new (&m_stride) StrideBase(StrideType::OuterStrideAtCompileTime==0?0:expr.outerStride(), - StrideType::InnerStrideAtCompileTime==0?0:expr.innerStride()); - } - - StrideBase m_stride; -}; - - -template class Ref - : public RefBase > -{ - private: - typedef internal::traits Traits; - template - inline Ref(const PlainObjectBase& expr, - typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0); - public: - - typedef RefBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(Ref) - - - #ifndef EIGEN_PARSED_BY_DOXYGEN - template - inline Ref(PlainObjectBase& expr, - typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) - { - EIGEN_STATIC_ASSERT(static_cast(Traits::template match::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); - Base::construct(expr.derived()); - } - template - inline Ref(const DenseBase& expr, - typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) - #else - template - inline Ref(DenseBase& expr) - #endif - { - EIGEN_STATIC_ASSERT(static_cast(internal::is_lvalue::value), THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); - EIGEN_STATIC_ASSERT(static_cast(Traits::template match::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); - enum { THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY = Derived::ThisConstantIsPrivateInPlainObjectBase}; - Base::construct(expr.const_cast_derived()); - } - - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Ref) - -}; - -// this is the const ref version -template class Ref - : public RefBase > -{ - typedef internal::traits Traits; - public: - - typedef RefBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(Ref) - - template - inline Ref(const DenseBase& expr, - typename internal::enable_if::ScalarTypeMatch),Derived>::type* = 0) - { -// std::cout << match_helper::HasDirectAccess << "," << match_helper::OuterStrideMatch << "," << match_helper::InnerStrideMatch << "\n"; -// std::cout << int(StrideType::OuterStrideAtCompileTime) << " - " << int(Derived::OuterStrideAtCompileTime) << "\n"; -// std::cout << int(StrideType::InnerStrideAtCompileTime) << " - " << int(Derived::InnerStrideAtCompileTime) << "\n"; - construct(expr.derived(), typename Traits::template match::type()); - } - - inline Ref(const Ref& other) : Base(other) { - // copy constructor shall not copy the m_object, to avoid unnecessary malloc and copy - } - - template - inline Ref(const RefBase& other) { - construct(other.derived(), typename Traits::template match::type()); - } - - protected: - - template - void construct(const Expression& expr,internal::true_type) - { - Base::construct(expr); - } - - template - void construct(const Expression& expr, internal::false_type) - { - m_object.lazyAssign(expr); - Base::construct(m_object); - } - - protected: - TPlainObjectType m_object; -}; - -} // end namespace Eigen - -#endif // EIGEN_REF_H diff --git a/splinter/src/Core/Replicate.h b/splinter/src/Core/Replicate.h deleted file mode 100644 index ac4537c142..0000000000 --- a/splinter/src/Core/Replicate.h +++ /dev/null @@ -1,177 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_REPLICATE_H -#define EIGEN_REPLICATE_H - -namespace Eigen { - -/** - * \class Replicate - * \ingroup Core_Module - * - * \brief Expression of the multiple replication of a matrix or vector - * - * \param MatrixType the type of the object we are replicating - * - * This class represents an expression of the multiple replication of a matrix or vector. - * It is the return type of DenseBase::replicate() and most of the time - * this is the only way it is used. - * - * \sa DenseBase::replicate() - */ - -namespace internal { -template -struct traits > - : traits -{ - typedef typename MatrixType::Scalar Scalar; - typedef typename traits::StorageKind StorageKind; - typedef typename traits::XprKind XprKind; - enum { - Factor = (RowFactor==Dynamic || ColFactor==Dynamic) ? Dynamic : RowFactor*ColFactor - }; - typedef typename nested::type MatrixTypeNested; - typedef typename remove_reference::type _MatrixTypeNested; - enum { - RowsAtCompileTime = RowFactor==Dynamic || int(MatrixType::RowsAtCompileTime)==Dynamic - ? Dynamic - : RowFactor * MatrixType::RowsAtCompileTime, - ColsAtCompileTime = ColFactor==Dynamic || int(MatrixType::ColsAtCompileTime)==Dynamic - ? Dynamic - : ColFactor * MatrixType::ColsAtCompileTime, - //FIXME we don't propagate the max sizes !!! - MaxRowsAtCompileTime = RowsAtCompileTime, - MaxColsAtCompileTime = ColsAtCompileTime, - IsRowMajor = MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1 ? 1 - : MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1 ? 0 - : (MatrixType::Flags & RowMajorBit) ? 1 : 0, - Flags = (_MatrixTypeNested::Flags & HereditaryBits & ~RowMajorBit) | (IsRowMajor ? RowMajorBit : 0), - CoeffReadCost = _MatrixTypeNested::CoeffReadCost - }; -}; -} - -template class Replicate - : public internal::dense_xpr_base< Replicate >::type -{ - typedef typename internal::traits::MatrixTypeNested MatrixTypeNested; - typedef typename internal::traits::_MatrixTypeNested _MatrixTypeNested; - public: - - typedef typename internal::dense_xpr_base::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(Replicate) - - template - inline explicit Replicate(const OriginalMatrixType& a_matrix) - : m_matrix(a_matrix), m_rowFactor(RowFactor), m_colFactor(ColFactor) - { - EIGEN_STATIC_ASSERT((internal::is_same::type,OriginalMatrixType>::value), - THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE) - eigen_assert(RowFactor!=Dynamic && ColFactor!=Dynamic); - } - - template - inline Replicate(const OriginalMatrixType& a_matrix, Index rowFactor, Index colFactor) - : m_matrix(a_matrix), m_rowFactor(rowFactor), m_colFactor(colFactor) - { - EIGEN_STATIC_ASSERT((internal::is_same::type,OriginalMatrixType>::value), - THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE) - } - - inline Index rows() const { return m_matrix.rows() * m_rowFactor.value(); } - inline Index cols() const { return m_matrix.cols() * m_colFactor.value(); } - - inline Scalar coeff(Index rowId, Index colId) const - { - // try to avoid using modulo; this is a pure optimization strategy - const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 - : RowFactor==1 ? rowId - : rowId%m_matrix.rows(); - const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 - : ColFactor==1 ? colId - : colId%m_matrix.cols(); - - return m_matrix.coeff(actual_row, actual_col); - } - template - inline PacketScalar packet(Index rowId, Index colId) const - { - const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 - : RowFactor==1 ? rowId - : rowId%m_matrix.rows(); - const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 - : ColFactor==1 ? colId - : colId%m_matrix.cols(); - - return m_matrix.template packet(actual_row, actual_col); - } - - const _MatrixTypeNested& nestedExpression() const - { - return m_matrix; - } - - protected: - MatrixTypeNested m_matrix; - const internal::variable_if_dynamic m_rowFactor; - const internal::variable_if_dynamic m_colFactor; -}; - -/** - * \return an expression of the replication of \c *this - * - * Example: \include MatrixBase_replicate.cpp - * Output: \verbinclude MatrixBase_replicate.out - * - * \sa VectorwiseOp::replicate(), DenseBase::replicate(Index,Index), class Replicate - */ -template -template -const Replicate -DenseBase::replicate() const -{ - return Replicate(derived()); -} - -/** - * \return an expression of the replication of \c *this - * - * Example: \include MatrixBase_replicate_int_int.cpp - * Output: \verbinclude MatrixBase_replicate_int_int.out - * - * \sa VectorwiseOp::replicate(), DenseBase::replicate(), class Replicate - */ -template -const typename DenseBase::ReplicateReturnType -DenseBase::replicate(Index rowFactor,Index colFactor) const -{ - return Replicate(derived(),rowFactor,colFactor); -} - -/** - * \return an expression of the replication of each column (or row) of \c *this - * - * Example: \include DirectionWise_replicate_int.cpp - * Output: \verbinclude DirectionWise_replicate_int.out - * - * \sa VectorwiseOp::replicate(), DenseBase::replicate(), class Replicate - */ -template -const typename VectorwiseOp::ReplicateReturnType -VectorwiseOp::replicate(Index factor) const -{ - return typename VectorwiseOp::ReplicateReturnType - (_expression(),Direction==Vertical?factor:1,Direction==Horizontal?factor:1); -} - -} // end namespace Eigen - -#endif // EIGEN_REPLICATE_H diff --git a/splinter/src/Core/ReturnByValue.h b/splinter/src/Core/ReturnByValue.h deleted file mode 100644 index f635598dcc..0000000000 --- a/splinter/src/Core/ReturnByValue.h +++ /dev/null @@ -1,99 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009-2010 Gael Guennebaud -// Copyright (C) 2009-2010 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_RETURNBYVALUE_H -#define EIGEN_RETURNBYVALUE_H - -namespace Eigen { - -/** \class ReturnByValue - * \ingroup Core_Module - * - */ - -namespace internal { - -template -struct traits > - : public traits::ReturnType> -{ - enum { - // We're disabling the DirectAccess because e.g. the constructor of - // the Block-with-DirectAccess expression requires to have a coeffRef method. - // Also, we don't want to have to implement the stride stuff. - Flags = (traits::ReturnType>::Flags - | EvalBeforeNestingBit) & ~DirectAccessBit - }; -}; - -/* The ReturnByValue object doesn't even have a coeff() method. - * So the only way that nesting it in an expression can work, is by evaluating it into a plain matrix. - * So internal::nested always gives the plain return matrix type. - * - * FIXME: I don't understand why we need this specialization: isn't this taken care of by the EvalBeforeNestingBit ?? - */ -template -struct nested, n, PlainObject> -{ - typedef typename traits::ReturnType type; -}; - -} // end namespace internal - -template class ReturnByValue - : internal::no_assignment_operator, public internal::dense_xpr_base< ReturnByValue >::type -{ - public: - typedef typename internal::traits::ReturnType ReturnType; - - typedef typename internal::dense_xpr_base::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(ReturnByValue) - - template - inline void evalTo(Dest& dst) const - { static_cast(this)->evalTo(dst); } - inline Index rows() const { return static_cast(this)->rows(); } - inline Index cols() const { return static_cast(this)->cols(); } - -#ifndef EIGEN_PARSED_BY_DOXYGEN -#define Unusable YOU_ARE_TRYING_TO_ACCESS_A_SINGLE_COEFFICIENT_IN_A_SPECIAL_EXPRESSION_WHERE_THAT_IS_NOT_ALLOWED_BECAUSE_THAT_WOULD_BE_INEFFICIENT - class Unusable{ - Unusable(const Unusable&) {} - Unusable& operator=(const Unusable&) {return *this;} - }; - const Unusable& coeff(Index) const { return *reinterpret_cast(this); } - const Unusable& coeff(Index,Index) const { return *reinterpret_cast(this); } - Unusable& coeffRef(Index) { return *reinterpret_cast(this); } - Unusable& coeffRef(Index,Index) { return *reinterpret_cast(this); } - template Unusable& packet(Index) const; - template Unusable& packet(Index, Index) const; -#endif -}; - -template -template -Derived& DenseBase::operator=(const ReturnByValue& other) -{ - other.evalTo(derived()); - return derived(); -} - -template -template -Derived& DenseBase::lazyAssign(const ReturnByValue& other) -{ - other.evalTo(derived()); - return derived(); -} - - -} // end namespace Eigen - -#endif // EIGEN_RETURNBYVALUE_H diff --git a/splinter/src/Core/Reverse.h b/splinter/src/Core/Reverse.h deleted file mode 100644 index e30ae3d281..0000000000 --- a/splinter/src/Core/Reverse.h +++ /dev/null @@ -1,224 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2006-2008 Benoit Jacob -// Copyright (C) 2009 Ricard Marxer -// Copyright (C) 2009-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_REVERSE_H -#define EIGEN_REVERSE_H - -namespace Eigen { - -/** \class Reverse - * \ingroup Core_Module - * - * \brief Expression of the reverse of a vector or matrix - * - * \param MatrixType the type of the object of which we are taking the reverse - * - * This class represents an expression of the reverse of a vector. - * It is the return type of MatrixBase::reverse() and VectorwiseOp::reverse() - * and most of the time this is the only way it is used. - * - * \sa MatrixBase::reverse(), VectorwiseOp::reverse() - */ - -namespace internal { - -template -struct traits > - : traits -{ - typedef typename MatrixType::Scalar Scalar; - typedef typename traits::StorageKind StorageKind; - typedef typename traits::XprKind XprKind; - typedef typename nested::type MatrixTypeNested; - typedef typename remove_reference::type _MatrixTypeNested; - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime, - MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, - - // let's enable LinearAccess only with vectorization because of the product overhead - LinearAccess = ( (Direction==BothDirections) && (int(_MatrixTypeNested::Flags)&PacketAccessBit) ) - ? LinearAccessBit : 0, - - Flags = int(_MatrixTypeNested::Flags) & (HereditaryBits | LvalueBit | PacketAccessBit | LinearAccess), - - CoeffReadCost = _MatrixTypeNested::CoeffReadCost - }; -}; - -template struct reverse_packet_cond -{ - static inline PacketScalar run(const PacketScalar& x) { return preverse(x); } -}; - -template struct reverse_packet_cond -{ - static inline PacketScalar run(const PacketScalar& x) { return x; } -}; - -} // end namespace internal - -template class Reverse - : public internal::dense_xpr_base< Reverse >::type -{ - public: - - typedef typename internal::dense_xpr_base::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(Reverse) - using Base::IsRowMajor; - - // next line is necessary because otherwise const version of operator() - // is hidden by non-const version defined in this file - using Base::operator(); - - protected: - enum { - PacketSize = internal::packet_traits::size, - IsColMajor = !IsRowMajor, - ReverseRow = (Direction == Vertical) || (Direction == BothDirections), - ReverseCol = (Direction == Horizontal) || (Direction == BothDirections), - OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1, - OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1, - ReversePacket = (Direction == BothDirections) - || ((Direction == Vertical) && IsColMajor) - || ((Direction == Horizontal) && IsRowMajor) - }; - typedef internal::reverse_packet_cond reverse_packet; - public: - - inline Reverse(const MatrixType& matrix) : m_matrix(matrix) { } - - EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Reverse) - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - - inline Index innerStride() const - { - return -m_matrix.innerStride(); - } - - inline Scalar& operator()(Index row, Index col) - { - eigen_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); - return coeffRef(row, col); - } - - inline Scalar& coeffRef(Index row, Index col) - { - return m_matrix.const_cast_derived().coeffRef(ReverseRow ? m_matrix.rows() - row - 1 : row, - ReverseCol ? m_matrix.cols() - col - 1 : col); - } - - inline CoeffReturnType coeff(Index row, Index col) const - { - return m_matrix.coeff(ReverseRow ? m_matrix.rows() - row - 1 : row, - ReverseCol ? m_matrix.cols() - col - 1 : col); - } - - inline CoeffReturnType coeff(Index index) const - { - return m_matrix.coeff(m_matrix.size() - index - 1); - } - - inline Scalar& coeffRef(Index index) - { - return m_matrix.const_cast_derived().coeffRef(m_matrix.size() - index - 1); - } - - inline Scalar& operator()(Index index) - { - eigen_assert(index >= 0 && index < m_matrix.size()); - return coeffRef(index); - } - - template - inline const PacketScalar packet(Index row, Index col) const - { - return reverse_packet::run(m_matrix.template packet( - ReverseRow ? m_matrix.rows() - row - OffsetRow : row, - ReverseCol ? m_matrix.cols() - col - OffsetCol : col)); - } - - template - inline void writePacket(Index row, Index col, const PacketScalar& x) - { - m_matrix.const_cast_derived().template writePacket( - ReverseRow ? m_matrix.rows() - row - OffsetRow : row, - ReverseCol ? m_matrix.cols() - col - OffsetCol : col, - reverse_packet::run(x)); - } - - template - inline const PacketScalar packet(Index index) const - { - return internal::preverse(m_matrix.template packet( m_matrix.size() - index - PacketSize )); - } - - template - inline void writePacket(Index index, const PacketScalar& x) - { - m_matrix.const_cast_derived().template writePacket(m_matrix.size() - index - PacketSize, internal::preverse(x)); - } - - const typename internal::remove_all::type& - nestedExpression() const - { - return m_matrix; - } - - protected: - typename MatrixType::Nested m_matrix; -}; - -/** \returns an expression of the reverse of *this. - * - * Example: \include MatrixBase_reverse.cpp - * Output: \verbinclude MatrixBase_reverse.out - * - */ -template -inline typename DenseBase::ReverseReturnType -DenseBase::reverse() -{ - return derived(); -} - -/** This is the const version of reverse(). */ -template -inline const typename DenseBase::ConstReverseReturnType -DenseBase::reverse() const -{ - return derived(); -} - -/** This is the "in place" version of reverse: it reverses \c *this. - * - * In most cases it is probably better to simply use the reversed expression - * of a matrix. However, when reversing the matrix data itself is really needed, - * then this "in-place" version is probably the right choice because it provides - * the following additional features: - * - less error prone: doing the same operation with .reverse() requires special care: - * \code m = m.reverse().eval(); \endcode - * - this API allows to avoid creating a temporary (the current implementation creates a temporary, but that could be avoided using swap) - * - it allows future optimizations (cache friendliness, etc.) - * - * \sa reverse() */ -template -inline void DenseBase::reverseInPlace() -{ - derived() = derived().reverse().eval(); -} - -} // end namespace Eigen - -#endif // EIGEN_REVERSE_H diff --git a/splinter/src/Core/Select.h b/splinter/src/Core/Select.h deleted file mode 100644 index 87993bbb55..0000000000 --- a/splinter/src/Core/Select.h +++ /dev/null @@ -1,162 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_SELECT_H -#define EIGEN_SELECT_H - -namespace Eigen { - -/** \class Select - * \ingroup Core_Module - * - * \brief Expression of a coefficient wise version of the C++ ternary operator ?: - * - * \param ConditionMatrixType the type of the \em condition expression which must be a boolean matrix - * \param ThenMatrixType the type of the \em then expression - * \param ElseMatrixType the type of the \em else expression - * - * This class represents an expression of a coefficient wise version of the C++ ternary operator ?:. - * It is the return type of DenseBase::select() and most of the time this is the only way it is used. - * - * \sa DenseBase::select(const DenseBase&, const DenseBase&) const - */ - -namespace internal { -template -struct traits > - : traits -{ - typedef typename traits::Scalar Scalar; - typedef Dense StorageKind; - typedef typename traits::XprKind XprKind; - typedef typename ConditionMatrixType::Nested ConditionMatrixNested; - typedef typename ThenMatrixType::Nested ThenMatrixNested; - typedef typename ElseMatrixType::Nested ElseMatrixNested; - enum { - RowsAtCompileTime = ConditionMatrixType::RowsAtCompileTime, - ColsAtCompileTime = ConditionMatrixType::ColsAtCompileTime, - MaxRowsAtCompileTime = ConditionMatrixType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = ConditionMatrixType::MaxColsAtCompileTime, - Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & HereditaryBits, - CoeffReadCost = traits::type>::CoeffReadCost - + EIGEN_SIZE_MAX(traits::type>::CoeffReadCost, - traits::type>::CoeffReadCost) - }; -}; -} - -template -class Select : internal::no_assignment_operator, - public internal::dense_xpr_base< Select >::type -{ - public: - - typedef typename internal::dense_xpr_base