diff --git a/.editorconfig b/.editorconfig index 7a915e98a..81950a9f5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,15 +12,15 @@ end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true -# C++ files want tab indentation +# SQL files want space indentation [*.sql] indent_style = space indent_size = 2 -# C++ files want tab indentation +# C++ files want space indentation [*.{c,h,cpp,hpp,inl}] indent_style = space -indent_size = 2 +indent_size = 4 # Makefiles want tab indentation [Makefile] diff --git a/CMakeLists.txt b/CMakeLists.txt index 03f8b1960..22f6ea2d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,8 +40,6 @@ add_definitions(-DPROJECT_VERSION="v${PROJECT_VERSION}${PROJECT_VERSION_DEV}") set(PROJECT_LIB_NAME "${PROJECT_NAME_LOWER}-${PROJECT_LIB_VERSION}") - - #============================================= # Set the working directories #============================================= @@ -297,7 +295,7 @@ endif() message(STATUS "VROOM_INSTALL_PATH ${VROOM_INSTALL_PATH}") -include_directories(${VROOM_INSTALL_PATH}/src) +include_directories(SYSTEM ${VROOM_INSTALL_PATH}/src) link_libraries(${VROOM_INSTALL_PATH}/lib/libvroom.a) link_libraries(glpk) diff --git a/NEWS.md b/NEWS.md index 50b199b36..cab8ec543 100644 --- a/NEWS.md +++ b/NEWS.md @@ -14,6 +14,7 @@ on Github. * Renamed files to be compiled as C++ with .hpp & .cpp extensions * Moved sphinx doc from .c files .rst files +* removing prefix `pgr_` & addding `namespace vrprouting` **Documentation queries** diff --git a/doc/_static/custom.css b/doc/_static/custom.css index 389a4f28c..19da7b807 100644 --- a/doc/_static/custom.css +++ b/doc/_static/custom.css @@ -11,5 +11,46 @@ div.content-wrapper { } div.topic { - border: none; + border: none; +} + +p.admonition-title { + font-weight: bold; + background-color: aqua; + border: #000000; +} + +.alert-warning { + color: #333; +} + +.alert-info { + color: #333; +} + +div.note { + background-color: white; + background-image: none; +} + +div.warning { + background-color: white; + background-image: none; +} + +div.signatures { + font-family: Menlo,Monaco,Consolas,"Courier New",monospace; + background-image: none; + background-color: #f5f5f5; + border: 1px solid #ccc; + color: #333; + font-size: 13px; + word-break: keep-all; + hyphens: none; +} + +code.literal { + color: #404040; + background-color: #e8e8e8; + font-size: 100% } diff --git a/doc/general/release_notes.rst b/doc/general/release_notes.rst index 95ee1d84b..e09ba3365 100644 --- a/doc/general/release_notes.rst +++ b/doc/general/release_notes.rst @@ -49,6 +49,7 @@ on Github. * Renamed files to be compiled as C++ with .hpp & .cpp extensions * Moved sphinx doc from .c files .rst files +* removing prefix `pgr_` & addding `namespace vrprouting` .. rubric:: Documentation queries diff --git a/doxygen/Doxyfile.in b/doxygen/Doxyfile.in index 04e210607..7dc98cdee 100644 --- a/doxygen/Doxyfile.in +++ b/doxygen/Doxyfile.in @@ -1,4 +1,4 @@ -# Doxyfile 1.8.7 +# Doxyfile 1.9.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -17,11 +17,11 @@ # Project related configuration options #--------------------------------------------------------------------------- -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all text -# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv -# for the list of possible encodings. +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 @@ -46,10 +46,10 @@ PROJECT_NUMBER = "@PROJECT_SHORT_VERSION@" PROJECT_BRIEF = "@PROJECT_BRIEF@" -# With the PROJECT_LOGO tag one can specify an logo or icon that is included in -# the documentation. The maximum height of the logo should not exceed 55 pixels -# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo -# to the output directory. +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. PROJECT_LOGO = @CMAKE_CURRENT_SOURCE_DIR@/../doc/_static/images/vrprouting-logo.png @@ -60,7 +60,7 @@ PROJECT_LOGO = @CMAKE_CURRENT_SOURCE_DIR@/../doc/_static/images/vrprou OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@ -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where @@ -76,7 +76,7 @@ CREATE_SUBDIRS = NO # U+3044. # The default value is: NO. -#ALLOW_UNICODE_NAMES = NO +ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this @@ -93,14 +93,22 @@ CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English -# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES -# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the @@ -135,7 +143,7 @@ ALWAYS_DETAILED_SEC = YES INLINE_INHERITED_MEMB = YES -# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. @@ -177,7 +185,17 @@ SHORT_NAMES = NO # description.) # The default value is: NO. -JAVADOC_AUTOBRIEF = YES +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If @@ -185,7 +203,7 @@ JAVADOC_AUTOBRIEF = YES # requiring an explicit \brief command for a brief description.) # The default value is: NO. -QT_AUTOBRIEF = YES +QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as @@ -199,15 +217,23 @@ QT_AUTOBRIEF = YES MULTILINE_CPP_IS_BRIEF = NO +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a -# new page for each member. If set to NO, the documentation of a member will be -# part of the file/class/namespace that contains it. +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO @@ -226,16 +252,15 @@ TAB_SIZE = 4 # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines. +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) ALIASES = -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all @@ -264,28 +289,40 @@ OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: -# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: -# Fortran. In the later case the parser tries to guess whether the code is fixed -# or free formatted code, this is the default for Fortran type files), VHDL. For -# instance to make doxygen treat .inc files as Fortran files (default is PHP), -# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. # -# Note For files without extension you can use no_extension as a placeholder. +# Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. +# documentation. See https://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. @@ -293,10 +330,19 @@ EXTENSION_MAPPING = MARKDOWN_SUPPORT = YES +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by by putting a % sign in front of the word -# or globally by setting AUTOLINK_SUPPORT to NO. +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES @@ -318,7 +364,7 @@ BUILTIN_STL_SUPPORT = YES CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. @@ -336,13 +382,20 @@ SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first +# tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent @@ -397,11 +450,24 @@ TYPEDEF_HIDES_STRUCT = NO LOOKUP_CACHE_SIZE = 0 +# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which efficively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 2 + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. @@ -411,35 +477,35 @@ LOOKUP_CACHE_SIZE = 0 EXTRACT_ALL = YES -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = YES -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = YES -# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = YES -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined -# locally in source files will be included in the documentation. If set to NO +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES -# This flag is only useful for Objective-C code. When set to YES local methods, +# This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are -# included in the documentation. If set to NO only methods in the interface are +# included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. @@ -452,7 +518,14 @@ EXTRACT_LOCAL_METHODS = NO # are hidden. # The default value is: NO. -EXTRACT_ANON_NSPACES = YES +EXTRACT_ANON_NSPACES = NO + +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these @@ -464,21 +537,21 @@ HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set -# to NO these classes will be included in the various overviews. This option has -# no effect if EXTRACT_ALL is enabled. +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO these declarations will be -# included in the documentation. +# declarations. If set to NO, these declarations will be included in the +# documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any -# documentation blocks found inside the body of a function. If set to NO these +# documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. @@ -491,22 +564,36 @@ HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO -# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. # The default value is: system dependent. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with -# their full class and namespace scopes in the documentation. If set to YES the +# their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. @@ -515,7 +602,7 @@ SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader - +# which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = YES @@ -534,14 +621,14 @@ INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. +# name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. Note that +# name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. @@ -586,27 +673,25 @@ SORT_BY_SCOPE_NAME = YES STRICT_PROTO_MATCHING = YES -# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the -# todo list. This list is created by putting \todo commands in the -# documentation. +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES -# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the -# test list. This list is created by putting \test commands in the -# documentation. +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES -# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES -# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. @@ -631,8 +716,8 @@ ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at -# the bottom of the documentation of classes and structs. If set to YES the list -# will mention the files that were used to generate the documentation. +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES @@ -677,11 +762,10 @@ LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the -# search path. Do not use file names with spaces, bibtex cannot handle them. See -# also \cite for info how to create references. +# search path. See also \cite for info how to create references. CITE_BIB_FILES = @@ -697,7 +781,7 @@ CITE_BIB_FILES = QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are -# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. @@ -705,7 +789,7 @@ QUIET = YES WARNINGS = YES -# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. @@ -722,12 +806,22 @@ WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO doxygen will only warn about wrong or incomplete parameter -# documentation, but not about the absence of documentation. +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. # The default value is: NO. WARN_NO_PARAMDOC = YES +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# The default value is: NO. + +WARN_AS_ERROR = FAIL_ON_WARNINGS + # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated @@ -742,7 +836,7 @@ WARN_FORMAT = "$file:$line: $text" # messages should be written. If left blank the output is written to standard # error (stderr). -WARN_LOGFILE = ./LOG +WARN_LOGFILE = @CMAKE_CURRENT_BIN_DIR@/LOG #--------------------------------------------------------------------------- # Configuration options related to the input files @@ -751,30 +845,41 @@ WARN_LOGFILE = ./LOG # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with -# spaces. +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = @CMAKE_CURRENT_SOURCE_DIR@/../src @CMAKE_CURRENT_SOURCE_DIR@/../include @CMAKE_CURRENT_SOURCE_DIR@ +INPUT = @CMAKE_SOURCE_DIR@/src @CMAKE_SOURCE_DIR@/include @CMAKE_CURRENT_SOURCE_DIR@ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of -# possible encodings. +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank the -# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, -# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, -# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, -# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, -# *.qsf, *.as and *.js. +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), +# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl, +# *.ucf, *.qsf and *.ice. -FILE_PATTERNS = +FILE_PATTERNS = *.c *.h \ + *.cpp *.hpp \ + *.dox # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. @@ -790,7 +895,6 @@ RECURSIVE = YES # run. EXCLUDE = -# ../../tools ../../doc ../../build ../../cmake ../../.tx # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -806,7 +910,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = */notUsed/* */test/* */src/trsp/doc/README.md +EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -823,7 +927,7 @@ EXCLUDE_SYMBOLS = # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/../src @CMAKE_CURRENT_SOURCE_DIR@/../sql +EXAMPLE_PATH = @CMAKE_SOURCE_DIR@/src @CMAKE_SOURCE_DIR@/sql # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and @@ -843,8 +947,7 @@ EXAMPLE_RECURSIVE = NO # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/../doc/_static/images/developers - +IMAGE_PATH = @CMAKE_SOURCE_DIR@/doc/_static/images/developers # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -860,6 +963,10 @@ IMAGE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/../doc/_static/images/develo # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. INPUT_FILTER = @@ -869,11 +976,15 @@ INPUT_FILTER = # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER ) will also be used to filter the input files that are used for +# INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. @@ -892,7 +1003,7 @@ FILTER_SOURCE_PATTERNS = # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = ../../README.md +USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing @@ -921,7 +1032,7 @@ INLINE_SOURCES = YES STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# function all documented functions referencing it will be listed. +# entity all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = YES @@ -933,7 +1044,7 @@ REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set -# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. @@ -953,12 +1064,12 @@ SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version +# (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # @@ -980,6 +1091,44 @@ USE_HTAGS = NO VERBATIM_HEADERS = YES +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: +# http://clang.llvm.org/) for more accurate parsing at the cost of reduced +# performance. This can be particularly helpful with template rich C++ code for +# which doxygen's built-in parser lacks the necessary type information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to +# YES then doxygen will add the directory of each input to the include path. +# The default value is: YES. + +CLANG_ADD_INC_PATHS = YES + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the directory containing a file called compile_commands.json. This +# file is the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the +# options used when the source files were built. This is equivalent to +# specifying the -p option to a clang tool, such as clang-check. These options +# will then be passed to the parser. Any options specified with CLANG_OPTIONS +# will be added as well. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = + #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- @@ -991,13 +1140,6 @@ VERBATIM_HEADERS = YES ALPHABETICAL_INDEX = YES -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 5 - # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored @@ -1010,7 +1152,7 @@ IGNORE_PREFIX = # Configuration options related to the HTML output #--------------------------------------------------------------------------- -# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES @@ -1072,13 +1214,15 @@ HTML_FOOTER = HTML_STYLESHEET = -# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- -# defined cascading style sheet that is included after the standard style sheets +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. -# Doxygen will copy the style sheet file to the output directory. For an example -# see the documentation. +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = @@ -1094,9 +1238,9 @@ HTML_EXTRA_STYLESHEET = HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen -# will adjust the colors in the stylesheet and background images according to +# will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. @@ -1125,12 +1269,24 @@ HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: YES. +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. @@ -1154,13 +1310,14 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with -# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a -# Makefile in the HTML output directory. Running make will produce the docset in -# that directory and running make install will install the docset in +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1199,8 +1356,8 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. +# (see: +# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML @@ -1222,28 +1379,28 @@ GENERATE_HTMLHELP = NO CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path -# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = -# The GENERATE_CHI flag controls if a separate .chi index file is generated ( -# YES) or that it should be included in the master .chm file ( NO). +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO -# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = -# The BINARY_TOC flag controls whether a binary table of contents is generated ( -# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1275,7 +1432,8 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1283,8 +1441,8 @@ QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- -# folders). +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1292,30 +1450,30 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = -# The QHG_LOCATION tag can be used to specify the location of Qt's -# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the -# generated .qhp file. +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = @@ -1357,7 +1515,7 @@ DISABLE_INDEX = NO # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the -# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has @@ -1385,13 +1543,24 @@ ENUM_VALUES_PER_LINE = 4 TREEVIEW_WIDTH = 250 -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = YES +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML @@ -1412,9 +1581,15 @@ FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering -# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. @@ -1425,7 +1600,7 @@ USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. @@ -1440,8 +1615,8 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest @@ -1455,7 +1630,8 @@ MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1483,7 +1659,7 @@ MATHJAX_CODEFILE = SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a web server instead of a web client using Javascript. There +# implemented using a web server instead of a web client using JavaScript. There # are two flavors of web server based searching depending on the EXTERNAL_SEARCH # setting. When disabled, doxygen will generate a PHP script for searching and # an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing @@ -1500,9 +1676,10 @@ SERVER_BASED_SEARCH = NO # external search engine pointed to by the SEARCHENGINE_URL option to obtain the # search results. # -# Doxygen ships with an example indexer ( doxyindexer) and search engine +# Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). +# Xapian (see: +# https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1513,10 +1690,11 @@ EXTERNAL_SEARCH = NO # The SEARCHENGINE_URL should point to a search engine hosted by a web server # which will return the search results when EXTERNAL_SEARCH is enabled. # -# Doxygen ships with an example indexer ( doxyindexer) and search engine +# Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). See the section "External Indexing and -# Searching" for details. +# Xapian (see: +# https://xapian.org/). See the section "External Indexing and Searching" for +# details. # This tag requires that the tag SEARCHENGINE is set to YES. SEARCHENGINE_URL = @@ -1551,7 +1729,7 @@ EXTRA_SEARCH_MAPPINGS = # Configuration options related to the LaTeX output #--------------------------------------------------------------------------- -# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output. +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. # The default value is: YES. GENERATE_LATEX = YES @@ -1567,22 +1745,36 @@ LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. # -# Note that when enabling USE_PDFLATEX this option is only used for generating -# bitmaps for formulas in the HTML output, but not in the Makefile that is -# written to the output directory. -# The default file is: latex. +# Note that when not enabling USE_PDFLATEX the default is latex when enabling +# USE_PDFLATEX the default is pdflatex and when in the later case latex is +# chosen this is overwritten by pdflatex. For specific output languages the +# default can have been set differently, this depends on the implementation of +# the output language. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate # index for LaTeX. +# Note: This tag is used in the Makefile / make.bat. +# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file +# (.tex). # The default file is: makeindex. # This tag requires that the tag GENERATE_LATEX is set to YES. MAKEINDEX_CMD_NAME = makeindex -# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX +# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to +# generate index for LaTeX. In case there is no backslash (\) as first character +# it will be automatically added in the LaTeX code. +# Note: This tag is used in the generated output file (.tex). +# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat. +# The default value is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_MAKEINDEX_CMD = makeindex + +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. @@ -1600,9 +1792,12 @@ COMPACT_LATEX = NO PAPER_TYPE = letter # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names -# that should be included in the LaTeX output. To get the times font for -# instance you can specify -# EXTRA_PACKAGES=times +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} # If left blank no extra packages will be included. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1616,23 +1811,36 @@ EXTRA_PACKAGES = # # Note: Only use a user-defined header if you know what you are doing! The # following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will -# replace them by respectively the title of the page, the current date and time, -# only the current date, the version number of doxygen, the project name (see -# PROJECT_NAME), or the project number (see PROJECT_NUMBER). +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty +# string, for the replacement values of the other commands the user is referred +# to HTML_HEADER. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the # generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. +# chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. # # Note: Only use a user-defined footer if you know what you are doing! # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_FOOTER = +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = + # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the LATEX_OUTPUT output # directory. Note that the files will be copied as-is; there are no commands or @@ -1650,9 +1858,11 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES -# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate -# the PDF file directly from the LaTeX files. Set this option to YES to get a -# higher quality PDF documentation. +# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as +# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX +# files. Set this option to YES, to get a higher quality PDF documentation. +# +# See also section LATEX_CMD_NAME for selecting the engine. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1686,17 +1896,33 @@ LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See -# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_BIB_STYLE = plain +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO + +# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) +# path from which the emoji images will be read. If a relative path is entered, +# it will be relative to the LATEX_OUTPUT directory. If left blank the +# LATEX_OUTPUT directory will be used. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EMOJI_DIRECTORY = + #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- -# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The # RTF output is optimized for Word 97 and may not look too pretty with other RTF # readers/editors. # The default value is: NO. @@ -1711,7 +1937,7 @@ GENERATE_RTF = NO RTF_OUTPUT = rtf -# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. @@ -1731,9 +1957,9 @@ COMPACT_RTF = NO RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's config -# file, i.e. a series of assignments. You only have to provide replacements, -# missing definitions are set to their default value. +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# configuration file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. # # See also section "Doxygen usage" for information on how to generate the # default style sheet that doxygen normally uses. @@ -1742,17 +1968,27 @@ RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is -# similar to doxygen's config file. A template extensions file can be generated -# using doxygen -e rtf extensionFile. +# similar to doxygen's configuration file. A template extensions file can be +# generated using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_EXTENSIONS_FILE = +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code +# with syntax highlighting in the RTF output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_SOURCE_CODE = NO + #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- -# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for # classes and files. # The default value is: NO. @@ -1781,7 +2017,7 @@ MAN_EXTENSION = .3 # MAN_EXTENSION with the initial . removed. # This tag requires that the tag GENERATE_MAN is set to YES. -#MAN_SUBDIR = +MAN_SUBDIR = # If the MAN_LINKS tag is set to YES and doxygen generates man output, then it # will generate one additional man file for each entity documented in the real @@ -1796,7 +2032,7 @@ MAN_LINKS = NO # Configuration options related to the XML output #--------------------------------------------------------------------------- -# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that # captures the structure of the code including all documentation. # The default value is: NO. @@ -1810,7 +2046,7 @@ GENERATE_XML = NO XML_OUTPUT = xml -# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program # listings (including syntax highlighting and cross-referencing information) to # the XML output. Note that enabling this will significantly increase the size # of the XML output. @@ -1819,11 +2055,18 @@ XML_OUTPUT = xml XML_PROGRAMLISTING = YES +# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include +# namespace members in file scope as well, matching the HTML output. +# The default value is: NO. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_NS_MEMB_FILE_SCOPE = NO + #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- -# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files # that can be used to generate PDF. # The default value is: NO. @@ -1837,14 +2080,23 @@ GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the +# program listings (including syntax highlighting and cross-referencing +# information) to the DOCBOOK output. Note that enabling this will significantly +# increase the size of the DOCBOOK output. +# The default value is: NO. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_PROGRAMLISTING = NO + #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- -# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen -# Definitions (see http://autogen.sf.net) file that captures the structure of -# the code including all documentation. Note that this feature is still -# experimental and incomplete at the moment. +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# the structure of the code including all documentation. Note that this feature +# is still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO @@ -1853,7 +2105,7 @@ GENERATE_AUTOGEN_DEF = NO # Configuration options related to the Perl module output #--------------------------------------------------------------------------- -# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module # file that captures the structure of the code including all documentation. # # Note that this feature is still experimental and incomplete at the moment. @@ -1861,7 +2113,7 @@ GENERATE_AUTOGEN_DEF = NO GENERATE_PERLMOD = NO -# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary # Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI # output from the Perl module output. # The default value is: NO. @@ -1869,9 +2121,9 @@ GENERATE_PERLMOD = NO PERLMOD_LATEX = NO -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely # formatted so it can be parsed by a human reader. This is useful if you want to -# understand what is going on. On the other hand, if this tag is set to NO the +# understand what is going on. On the other hand, if this tag is set to NO, the # size of the Perl module output will be much smaller and Perl will parse it # just the same. # The default value is: YES. @@ -1891,14 +2143,14 @@ PERLMOD_MAKEVAR_PREFIX = # Configuration options related to the preprocessor #--------------------------------------------------------------------------- -# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all # C-preprocessor directives found in the sources and include files. # The default value is: YES. ENABLE_PREPROCESSING = YES -# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names -# in the source code. If set to NO only conditional compilation will be +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be # performed. Macro expansion can be done in a controlled way by setting # EXPAND_ONLY_PREDEF to YES. # The default value is: NO. @@ -1914,7 +2166,7 @@ MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = NO -# If the SEARCH_INCLUDES tag is set to YES the includes files in the +# If the SEARCH_INCLUDES tag is set to YES, the include files in the # INCLUDE_PATH will be searched if a #include is found. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. @@ -1990,20 +2242,21 @@ TAGFILES = GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES all external class will be listed in the -# class index. If set to NO only the inherited external classes will be listed. +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. # The default value is: NO. ALLEXTERNALS = NO -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in -# the modules index. If set to NO, only the current project's groups will be +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. EXTERNAL_GROUPS = YES -# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in # the related pages index. If set to NO, only the current project's pages will # be listed. # The default value is: YES. @@ -2014,7 +2267,7 @@ EXTERNAL_PAGES = YES # Configuration options related to the dot tool #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram # (in HTML and LaTeX) for classes with base or super classes. Setting the tag to # NO turns the diagrams off. Note that this option also works with HAVE_DOT # disabled, but it is recommended to install and use dot, since it yields more @@ -2030,7 +2283,7 @@ CLASS_DIAGRAMS = YES DIA_PATH = -# If set to YES, the inheritance and collaboration graphs will hide inheritance +# If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. @@ -2055,7 +2308,7 @@ HAVE_DOT = YES DOT_NUM_THREADS = 0 -# When you want a differently looking font n the dot files that doxygen +# When you want a differently looking font in the dot files that doxygen # generates you can specify the font name using DOT_FONTNAME. You need to make # sure dot is able to find the font, which can be done by putting it in a # standard location or by setting the DOTFONTPATH environment variable or by @@ -2103,7 +2356,7 @@ COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. # The default value is: NO. @@ -2120,10 +2373,32 @@ UML_LOOK = NO # but if the number exceeds 15, the total amount of fields shown is limited to # 10. # Minimum value: 0, maximum value: 100, default value: 10. -# This tag requires that the tag HAVE_DOT is set to YES. +# This tag requires that the tag UML_LOOK is set to YES. UML_LIMIT_NUM_FIELDS = 10 +# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and +# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS +# tag is set to YES, doxygen will add type and arguments for attributes and +# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen +# will not generate fields with class member information in the UML graphs. The +# class diagrams will look similar to the default class diagrams but using UML +# notation for the relationships. +# Possible values are: NO, YES and NONE. +# The default value is: NO. +# This tag requires that the tag UML_LOOK is set to YES. + +DOT_UML_DETAILS = NO + +# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters +# to display on a single line. If the actual line length exceeds this threshold +# significantly it will wrapped across multiple lines. Some heuristics are apply +# to avoid ugly line breaks. +# Minimum value: 0, maximum value: 1000, default value: 17. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_WRAP_THRESHOLD = 17 + # If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and # collaboration graphs will show the relations between templates and their # instances. @@ -2155,7 +2430,8 @@ INCLUDED_BY_GRAPH = YES # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2166,7 +2442,8 @@ CALL_GRAPH = NO # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2189,13 +2466,17 @@ GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). # Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd, # png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo, -# gif:cairo:gd, gif:gd, gif:gd:gd and svg. +# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2238,6 +2519,24 @@ MSCFILE_DIRS = DIAFILE_DIRS = +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file. If left blank, it is assumed +# PlantUML is not used or called during a preprocessing step. Doxygen will +# generate a warning when it encounters a \startuml command in this case and +# will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = + # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes # larger than this value, doxygen will truncate the graph, which is visualized @@ -2274,7 +2573,7 @@ MAX_DOT_GRAPH_DEPTH = 1 DOT_TRANSPARENT = NO -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support # this, this feature is disabled by default. @@ -2291,9 +2590,11 @@ DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate # files that are used to generate the various graphs. +# +# Note: This setting is not only used for dot files but also for msc and +# plantuml temporary files. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. -DOT_CLEANUP = NO +DOT_CLEANUP = YES diff --git a/include/c_common/e_report.h b/include/c_common/e_report.h index 501f8dd87..0500145c9 100644 --- a/include/c_common/e_report.h +++ b/include/c_common/e_report.h @@ -27,48 +27,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #define INCLUDE_C_COMMON_E_REPORT_H_ #pragma once -/*! @name Postgres ereport - * Send notice or error to postgreSQL (cleans the char *) - * - * From the C++ err_msg, log_msg, notice_msg are returned as a (char *), - * - * Before exiting the C code the pointers need to be freed: - * - This task can be done when there is no error, - * - Call to ERROR, gives the control back to postgreSQL - * - leaves a leak - * - * on C++ side, the message to be returned; - * ~~~~{.c} - * std::ostringstream log; - * log << "the message"; - * *log_msg = pgr_msg(log.str().c_str()); - * ~~~~ - * - * - * - * when there is ERROR then postgreSQL takes over control - * The char* messages are cleared automaticalyy with pfree. - * - * @warning When error: Free all data not created with palloc before calling - * - */ -/*! @brief notice & error - * - * ~~~~{.c} - * pgr_notice(&log_msg, ¬ice_msg, &error_msg); - * - * precondition: before calling ereport - * assert(!*log_msg); - * assert(!*notice_msg); - * assert(!*error_msg); - * ~~~~ - */ +/** @brief print log notice and error */ void -pgr_global_report( - char* log_msg, - char* notice_msg, - char* error_msg); - +vrp_global_report( + char** log_msg, + char** notice_msg, + char** error_msg); #endif // INCLUDE_C_COMMON_E_REPORT_H_ diff --git a/include/c_common/orders_input.h b/include/c_common/orders_input.h index 12a7defd4..6b2aa8261 100644 --- a/include/c_common/orders_input.h +++ b/include/c_common/orders_input.h @@ -27,27 +27,27 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #pragma once #include -typedef struct PickDeliveryOrders_t PickDeliveryOrders_t; +typedef struct Orders_t Orders_t; /** @brief Reads the pick-Deliver shipments for timestams and intervals*/ void get_shipments( char *, - PickDeliveryOrders_t **, + Orders_t **, size_t *); /** @brief Reads the pick-Deliver shipments for raw data*/ void get_shipments_raw( char *, - PickDeliveryOrders_t **, + Orders_t **, size_t *); /** @brief Reads the pick-Deliver shipments for euclidean information*/ void get_shipments_euclidean( char *, - PickDeliveryOrders_t **, + Orders_t **, size_t *); #endif // INCLUDE_C_COMMON_ORDERS_INPUT_H_ diff --git a/include/c_common/postgres_connection.h b/include/c_common/postgres_connection.h index 177d283dc..e2963782f 100644 --- a/include/c_common/postgres_connection.h +++ b/include/c_common/postgres_connection.h @@ -25,6 +25,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #define INCLUDE_C_COMMON_POSTGRES_CONNECTION_H_ #pragma once +#ifdef __cplusplus +extern "C" { +#endif #include #include @@ -34,11 +37,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include -void pgr_send_error(int errcode); -void pgr_SPI_finish(void); -void pgr_SPI_connect(void); -SPIPlanPtr pgr_SPI_prepare(char* sql); -Portal pgr_SPI_cursor_open(SPIPlanPtr SPIplan); -char* pgr_cstring2char(const char *inStr); +void vrp_SPI_finish(void); +void vrp_SPI_connect(void); +SPIPlanPtr vrp_SPI_prepare(const char*); +Portal vrp_SPI_cursor_open(SPIPlanPtr); + +#ifdef __cplusplus +} +#endif #endif // INCLUDE_C_COMMON_POSTGRES_CONNECTION_H_ diff --git a/include/c_types/typedefs.h b/include/c_types/typedefs.h index 84bb26cb2..9552621a4 100644 --- a/include/c_types/typedefs.h +++ b/include/c_types/typedefs.h @@ -47,7 +47,7 @@ using Priority = uint32_t; using Distance = uint32_t; using Skill = uint32_t; using StepType = int32_t; -using PickDeliveryOrders_t = struct PickDeliveryOrders_t; +using Orders_t = struct Orders_t; using Vehicle_t = struct Vehicle_t; using Matrix_cell_t = struct Matrix_cell_t; using Time_multipliers_t = struct Time_multipliers_t; @@ -84,7 +84,7 @@ typedef uint32_t Priority; typedef uint32_t Distance; typedef uint32_t Skill; typedef int32_t StepType; -typedef struct PickDeliveryOrders_t PickDeliveryOrders_t; +typedef struct Orders_t Orders_t; typedef struct Vehicle_t Vehicle_t; typedef struct Matrix_cell_t Matrix_cell_t; typedef struct Time_multipliers_t Time_multipliers_t; diff --git a/include/cpp_common/alloc.hpp b/include/cpp_common/alloc.hpp index 438618eb7..7e17d1ad7 100644 --- a/include/cpp_common/alloc.hpp +++ b/include/cpp_common/alloc.hpp @@ -45,7 +45,9 @@ SPI_pfree(void *pointer); } -/*! \fn pgr_alloc(std::size_t size, T *ptr) +namespace vrprouting { + +/*! \fn alloc(std::size_t size, T *ptr) \brief allocates memory @@ -63,7 +65,7 @@ SPI_pfree(void *pointer); template T* -pgr_alloc(std::size_t size, T* ptr) { +alloc(std::size_t size, T* ptr) { if (!ptr) { ptr = static_cast(SPI_palloc(size * sizeof(T))); } else { @@ -74,14 +76,15 @@ pgr_alloc(std::size_t size, T* ptr) { template T* -pgr_free(T* ptr) { +free(T* ptr) { if (ptr) { SPI_pfree(ptr); } return nullptr; } -char * -pgr_msg(const std::string &msg); +char* to_pg_msg(const std::string &); + +} // namespace vrprouting #endif // INCLUDE_CPP_COMMON_ALLOC_HPP_ diff --git a/include/cpp_common/messages.hpp b/include/cpp_common/messages.hpp index 3e9a363e0..dc42f527a 100644 --- a/include/cpp_common/messages.hpp +++ b/include/cpp_common/messages.hpp @@ -49,11 +49,11 @@ namespace vrprouting { * notice * error */ -class Pgr_messages { +class Messages { public: - Pgr_messages() = default; - Pgr_messages(const Pgr_messages&) {} - Pgr_messages& operator=(const Pgr_messages&) {return *this;} + Messages() = default; + Messages(const Messages&) {} + Messages& operator=(const Messages&) {return *this;} /*! @brief gets the contents of @b log message * diff --git a/include/cpp_common/orders_t.hpp b/include/cpp_common/orders_t.hpp index 06dcc56fd..9aa08c3f0 100644 --- a/include/cpp_common/orders_t.hpp +++ b/include/cpp_common/orders_t.hpp @@ -52,7 +52,7 @@ deliver_service_t | Deliver service duration /* * its with either (foo_x, foo_y) pairs (for euclidean or with foo_node_id (for matrix) */ -struct PickDeliveryOrders_t{ +struct Orders_t{ Id id; /** Order's identifier */ PAmount demand; /** Number of demand */ diff --git a/include/drivers/compatibleVehicles_driver.h b/include/drivers/compatibleVehicles_driver.h index 70661bc20..795447087 100644 --- a/include/drivers/compatibleVehicles_driver.h +++ b/include/drivers/compatibleVehicles_driver.h @@ -39,7 +39,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # include #endif -typedef struct PickDeliveryOrders_t PickDeliveryOrders_t; +typedef struct Orders_t Orders_t; typedef struct Time_multipliers_t Time_multipliers_t; typedef struct Vehicle_t Vehicle_t; typedef struct Matrix_cell_t Matrix_cell_t; @@ -51,7 +51,7 @@ extern "C" { /** @brief Driver for processing a "compatible vehicles" problem */ void do_compatibleVehicles( - PickDeliveryOrders_t customers_arr[], size_t total_customers, + Orders_t customers_arr[], size_t total_customers, Vehicle_t *vehicles_arr, size_t total_vehicles, Matrix_cell_t *matrix_cells_arr, size_t total_cells, Time_multipliers_t *multipliers_arr, size_t total_multipliers, diff --git a/include/drivers/optimize_driver.h b/include/drivers/optimize_driver.h index 2de6e557d..549266095 100644 --- a/include/drivers/optimize_driver.h +++ b/include/drivers/optimize_driver.h @@ -40,7 +40,7 @@ extern "C" { /** @brief Driver for processing a pickupDeliver problem */ void do_optimize( - PickDeliveryOrders_t customers_arr[], size_t, + Orders_t customers_arr[], size_t, Vehicle_t *vehicles_arr, size_t, Matrix_cell_t *, size_t, Time_multipliers_t *, size_t, diff --git a/include/drivers/pgr_pickDeliverEuclidean_driver.h b/include/drivers/pgr_pickDeliverEuclidean_driver.h index 8fada01b4..bc1156c7b 100644 --- a/include/drivers/pgr_pickDeliverEuclidean_driver.h +++ b/include/drivers/pgr_pickDeliverEuclidean_driver.h @@ -39,7 +39,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # include #endif -typedef struct PickDeliveryOrders_t PickDeliveryOrders_t; +typedef struct Orders_t Orders_t; typedef struct Solution_rt Solution_rt; typedef struct Vehicle_t Vehicle_t; @@ -54,7 +54,7 @@ extern "C" { max_cycles INTEGER, ********************************************************/ void do_pgr_pickDeliverEuclidean( - PickDeliveryOrders_t *pd_orders_arr, size_t total_pd_orders, + Orders_t *pd_orders_arr, size_t total_pd_orders, Vehicle_t *vehicles_arr, size_t total_vehicles, double factor, diff --git a/include/drivers/pgr_pickDeliver_driver.h b/include/drivers/pgr_pickDeliver_driver.h index a043c49ab..bff7a1641 100644 --- a/include/drivers/pgr_pickDeliver_driver.h +++ b/include/drivers/pgr_pickDeliver_driver.h @@ -42,7 +42,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "cpp_common/vehicle_t.hpp" #include "cpp_common/matrix_cell_t.hpp" -typedef struct PickDeliveryOrders_t PickDeliveryOrders_t; +typedef struct Orders_t Orders_t; typedef struct Solution_rt Solution_rt; #ifdef __cplusplus @@ -56,7 +56,7 @@ extern "C" { max_cycles INTEGER, ********************************************************/ void do_pgr_pickDeliver( - PickDeliveryOrders_t *pd_orders_arr, size_t total_pd_orders, + Orders_t *pd_orders_arr, size_t total_pd_orders, Vehicle_t *vehicles_arr, size_t total_vehicles, Matrix_cell_t *matrix_cells_arr, size_t total_cells, diff --git a/include/drivers/pickDeliver_driver.h b/include/drivers/pickDeliver_driver.h index 4461ead98..21a2bd726 100644 --- a/include/drivers/pickDeliver_driver.h +++ b/include/drivers/pickDeliver_driver.h @@ -40,7 +40,7 @@ extern "C" { /** @brief Driver for processing a pickupDeliver problem */ void do_pickDeliver( - PickDeliveryOrders_t customers_arr[], size_t total_customers, + Orders_t customers_arr[], size_t total_customers, Vehicle_t *vehicles_arr, size_t total_vehicles, Matrix_cell_t *matrix_cells_arr, size_t total_cells, Time_multipliers_t *multipliers_arr, size_t total_multipliers, diff --git a/include/problem/fleet.hpp b/include/problem/fleet.hpp index e9f2427d0..1de81e793 100644 --- a/include/problem/fleet.hpp +++ b/include/problem/fleet.hpp @@ -40,7 +40,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. typedef struct Vehicle_t Vehicle_t; namespace vrprouting { -class Pgr_messages; +class Messages; namespace problem { class Orders; @@ -120,7 +120,7 @@ class Fleet: protected std::vector { /** @brief set the vehicle's user's initial solution */ void set_initial_solution(const Orders&, Identifiers&, Identifiers&, TTimestamp, bool); - Pgr_messages& msg() {return m_msg;} + Messages& msg() {return m_msg;} protected: /** @brief add a new vehicle to the fleet */ @@ -146,7 +146,7 @@ class Fleet: protected std::vector { /** set of invalid vehicles */ Identifiers m_invalid; - mutable Pgr_messages m_msg; + mutable Messages m_msg; /* for the invariant */ size_t m_size; diff --git a/include/problem/orders.hpp b/include/problem/orders.hpp index a6dc73b6f..dd98b5ef5 100644 --- a/include/problem/orders.hpp +++ b/include/problem/orders.hpp @@ -52,7 +52,7 @@ class Orders : public std::vector { // todo remove template its problem::PickDeliver template - Orders(PickDeliveryOrders_t* p_orders, size_t p_size_orders, const PTR problem_ptr) { + Orders(Orders_t* p_orders, size_t p_size_orders, const PTR problem_ptr) { Tw_node::m_time_matrix_ptr = &problem_ptr->time_matrix(); build_orders(p_orders, p_size_orders, problem_ptr); } @@ -81,10 +81,10 @@ class Orders : public std::vector { private: template - void build_orders(PickDeliveryOrders_t *, size_t, const PTR problem_ptr); + void build_orders(Orders_t *, size_t, const PTR problem_ptr); /** @brief add in an order */ - void add_order(const PickDeliveryOrders_t &order, + void add_order(const Orders_t &order, const Vehicle_node &pick, const Vehicle_node &drop) { push_back(Order(size(), order.id, pick, drop)); @@ -98,12 +98,12 @@ class Orders : public std::vector { */ template void -Orders::build_orders(PickDeliveryOrders_t *orders, size_t size_orders, const PTR problem_ptr) { +Orders::build_orders(Orders_t *orders, size_t size_orders, const PTR problem_ptr) { /** * - Sort orders: ASC pick_open_t, deliver_close_t, id */ std::sort(orders, orders + size_orders, - [] (const PickDeliveryOrders_t &lhs, const PickDeliveryOrders_t &rhs) { + [] (const Orders_t &lhs, const Orders_t &rhs) { if (lhs.pick_open_t == rhs.pick_open_t) { if (lhs.deliver_close_t == rhs.deliver_close_t) { return lhs.id < rhs.id; diff --git a/include/problem/pickDeliver.hpp b/include/problem/pickDeliver.hpp index 6edb46b12..fac81e3ae 100644 --- a/include/problem/pickDeliver.hpp +++ b/include/problem/pickDeliver.hpp @@ -51,7 +51,7 @@ class PickDeliver { public: /** @brief General Constructor */ PickDeliver( - PickDeliveryOrders_t* p_orders, size_t p_orders_size, + Orders_t* p_orders, size_t p_orders_size, Vehicle_t* p_vehicles, size_t p_vehicles_size, const Matrix &p_cost_matrix) : m_cost_matrix(p_cost_matrix), @@ -65,7 +65,7 @@ class PickDeliver { /** @brief Override stops constructor */ PickDeliver( - PickDeliveryOrders_t* p_orders, size_t p_orders_size, + Orders_t* p_orders, size_t p_orders_size, Vehicle_t* p_vehicles, size_t p_vehicles_size, std::vector new_stops, const Matrix &p_cost_matrix) : @@ -96,7 +96,7 @@ class PickDeliver { const Fleet& vehicles() {return m_trucks;} /** message controller for all classes */ - Pgr_messages msg; + Messages msg; /** the cost matrix */ const Matrix& m_cost_matrix; diff --git a/include/problem/solution.hpp b/include/problem/solution.hpp index c3e6e06ff..ce40056bd 100644 --- a/include/problem/solution.hpp +++ b/include/problem/solution.hpp @@ -116,7 +116,7 @@ class Solution { bool operator<(const Solution&) const; - Pgr_messages& msg() {return m_msg;} + Messages& msg() {return m_msg;} const Orders& orders() const {return m_orders;} Fleet& vehicles() {return m_trucks;} @@ -127,7 +127,7 @@ class Solution { /** the problem info */ Orders m_orders; Fleet m_trucks; - Pgr_messages m_msg; + Messages m_msg; }; } // namespace problem diff --git a/include/problem/tw_node.hpp b/include/problem/tw_node.hpp index 7eeff17ed..e495a1ba5 100644 --- a/include/problem/tw_node.hpp +++ b/include/problem/tw_node.hpp @@ -59,7 +59,7 @@ class Tw_node : public Identifier { /** @brief Creating a Tw_node from a postgreSQL order */ Tw_node( size_t id, - const PickDeliveryOrders_t &data, + const Orders_t &data, const NodeType &type); /** @brief Creating a Tw_node from a postgreSQL vehicle */ diff --git a/include/problem/vehicle_pickDeliver.hpp b/include/problem/vehicle_pickDeliver.hpp index 82f6da6a3..cd176e75b 100644 --- a/include/problem/vehicle_pickDeliver.hpp +++ b/include/problem/vehicle_pickDeliver.hpp @@ -146,7 +146,7 @@ class Vehicle_pickDeliver : public Vehicle { const Orders& orders() const {pgassert(m_orders.size() != 0); return m_orders;} - Pgr_messages& msg() {return m_msg;} + Messages& msg() {return m_msg;} protected: using Vehicle::begin; @@ -164,7 +164,7 @@ class Vehicle_pickDeliver : public Vehicle { Orders m_orders; - Pgr_messages m_msg; + Messages m_msg; private: /** diff --git a/include/vroom/vroom.hpp b/include/vroom/vroom.hpp index 15e9033f4..4cbc5b210 100644 --- a/include/vroom/vroom.hpp +++ b/include/vroom/vroom.hpp @@ -51,599 +51,599 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. namespace vrprouting { -class Vrp_vroom_problem : public vrprouting::Pgr_messages { +class Vrp_vroom_problem : public vrprouting::Messages { public: - std::vector jobs() const { return m_jobs; } - std::vector> shipments() const { return m_shipments; } - std::vector vehicles() const { return m_vehicles; } - vrprouting::base::Base_Matrix matrix() const { return m_matrix; } - - /** - * @name vroom time window wrapper - */ - ///@{ - /** - * @brief Gets the vroom time window from the C-style struct - * - * @param[in] time_window The C-style time window struct - * - * @return The vroom time window. - */ - vroom::TimeWindow - get_vroom_time_window(const Vroom_time_window_t &time_window) const { - return - vroom::TimeWindow(time_window.tw_open, - time_window.tw_close); - } - - vroom::TimeWindow - get_vroom_time_window(Duration tw_open, Duration tw_close) const { - return vroom::TimeWindow(tw_open, tw_close); - } - - std::vector - get_vroom_time_windows( - const std::vector &time_windows) const { - std::vector < vroom::TimeWindow > tws; - for (auto time_window : time_windows) { - tws.push_back(get_vroom_time_window(time_window)); - } - if (tws.size()) { - return tws; - } else { - return std::vector(1, vroom::TimeWindow()); - } - } - ///@} - - - /** - * @name vroom amounts wrapper - */ - ///@{ - /** - * @brief Gets the vroom amounts from C-style array - * - * @param[in] amounts The amounts array (pickup or delivery) - * - * @return The vroom amounts. - */ - vroom::Amount - get_vroom_amounts(const std::vector &amounts) const { - vroom::Amount amt; - if (amounts.size()) { - for (auto amount : amounts) { - amt.push_back(amount); - } - } else { - const unsigned int amount_size = - m_vehicles.size() ? static_cast(m_vehicles[0].capacity.size()) : 0; - // Default to zero amount with provided size. - amt = vroom::Amount(amount_size); - for (size_t i = 0; i < amounts.size(); i++) { - amt[i] = amounts[i]; - } - } - return amt; - } - - vroom::Amount - get_vroom_amounts(const Amount *amounts, size_t count) const { - return get_vroom_amounts(std::vector (amounts, amounts + count)); - } - ///@} - - - /** - * @name vroom skills wrapper - */ - ///@{ - /** - * @brief Gets the vroom skills. - * - * @param[in] skills The skills array - * @param[in] count The size of skills array - * - * @return The vroom skills. - */ - vroom::Skills - get_vroom_skills(const Skill *skills, size_t count) const { - return std::unordered_set (skills, skills + count); - } - ///@} - - - /** - * @name vroom jobs wrapper - */ - ///@{ - /** - * @brief Gets the vroom jobs. - * - * @param[in] job The job C-style struct - * @param[in] job_tws The job time windows - * - * @return The vroom job. - */ - vroom::Job - get_vroom_job(const Vroom_job_t &job, - const std::vector &job_tws) const { - vroom::Amount delivery = - get_vroom_amounts(job.delivery, job.delivery_size); - vroom::Amount pickup = - get_vroom_amounts(job.pickup, job.pickup_size); - vroom::Skills skills = - get_vroom_skills(job.skills, job.skills_size); - std::vector time_windows = - get_vroom_time_windows(job_tws); - vroom::Index location_id = - static_cast(m_matrix.get_index(job.location_id)); - return vroom::Job(job.id, location_id, job.setup, job.service, delivery, pickup, - skills, job.priority, time_windows, job.data); - } - - void problem_add_job(const Vroom_job_t &job, - const std::vector &job_tws) { - m_jobs.push_back(get_vroom_job(job, job_tws)); - } - - void add_jobs(const std::vector &jobs, - const std::vector &jobs_tws) { - std::map> job_tws_map; - for (auto job_tw : jobs_tws) { - Idx id = job_tw.id; - if (job_tws_map.find(id) == job_tws_map.end()) { - job_tws_map[id] = std::vector(); - } - job_tws_map[id].push_back(job_tw); - } - for (auto job : jobs) { - problem_add_job(job, job_tws_map[job.id]); - } - } - - void add_jobs(const Vroom_job_t *jobs, size_t count, - const Vroom_time_window_t *jobs_tws, size_t total_jobs_tws) { - add_jobs( - std::vector(jobs, jobs + count), - std::vector(jobs_tws, jobs_tws + total_jobs_tws)); - } - ///@} - - - /** - * @name vroom shipments wrapper - */ - ///@{ - /** - * @brief Gets the vroom shipments. - * - * @param[in] shipment The shipment C-style struct - * @param[in] pickup_tws The pickup time windows - * @param[in] delivery_tws The delivery time windows - * - * @return The vroom shipment. - */ - std::pair get_vroom_shipment( - const Vroom_shipment_t &shipment, - const std::vector &pickup_tws, - const std::vector &delivery_tws) const { - vroom::Amount amount = - get_vroom_amounts(shipment.amount, shipment.amount_size); - vroom::Skills skills = - get_vroom_skills(shipment.skills, shipment.skills_size); - std::vector p_time_windows = - get_vroom_time_windows(pickup_tws); - std::vector d_time_windows = - get_vroom_time_windows(delivery_tws); - vroom::Index p_location_id = static_cast( - m_matrix.get_index(shipment.p_location_id)); - vroom::Index d_location_id = static_cast( - m_matrix.get_index(shipment.d_location_id)); - vroom::Job pickup = vroom::Job( - shipment.id, vroom::JOB_TYPE::PICKUP, p_location_id, - shipment.p_setup, shipment.p_service, amount, - skills, shipment.priority, p_time_windows, shipment.p_data); - vroom::Job delivery = vroom::Job( - shipment.id, vroom::JOB_TYPE::DELIVERY, d_location_id, - shipment.d_setup, shipment.d_service, amount, - skills, shipment.priority, d_time_windows, shipment.d_data); - return std::make_pair(pickup, delivery); - } - - void problem_add_shipment( - const Vroom_shipment_t &shipment, - const std::vector &pickup_tws, - const std::vector &delivery_tws) { - m_shipments.push_back( - get_vroom_shipment(shipment, pickup_tws, delivery_tws)); - } - - void add_shipments(const std::vector &shipments, - const std::vector &shipments_tws) { - std::map> pickup_tws_map; - std::map> delivery_tws_map; - for (auto shipment_tw : shipments_tws) { - Idx id = shipment_tw.id; - if (shipment_tw.kind == 'p') { - if (pickup_tws_map.find(id) == pickup_tws_map.end()) { - pickup_tws_map[id] = std::vector(); - } - pickup_tws_map[id].push_back(shipment_tw); - } else if (shipment_tw.kind == 'd') { - if (delivery_tws_map.find(id) == delivery_tws_map.end()) { - delivery_tws_map[id] = std::vector(); - } - delivery_tws_map[id].push_back(shipment_tw); - } - } - for (auto shipment : shipments) { - problem_add_shipment(shipment, pickup_tws_map[shipment.id], - delivery_tws_map[shipment.id]); - } - } - - void add_shipments(const Vroom_shipment_t *shipments, size_t count, - const Vroom_time_window_t *shipment_tws, size_t total_shipment_tws) { - add_shipments( - std::vector(shipments, shipments + count), - std::vector(shipment_tws, shipment_tws + total_shipment_tws)); - } - ///@} - - - /** - * @name vroom breaks wrapper - */ - ///@{ - /** - * @brief Gets the vehicle breaks from C-style breaks struct - * - * @param[in] v_break The vehicle break struct - * - * @return The vroom vehicle break. - */ - vroom::Break - get_vroom_break( - const Vroom_break_t &v_break, - const std::vector &break_tws) const { - std::vector tws = get_vroom_time_windows(break_tws); - return vroom::Break(v_break.id, tws, v_break.service, v_break.data); - } - - std::vector < vroom::Break > - get_vroom_breaks( - const std::vector &breaks, - const std::vector &breaks_tws) const { - std::map> breaks_tws_map; - for (auto break_tw : breaks_tws) { - Idx id = break_tw.id; - if (breaks_tws_map.find(id) == breaks_tws_map.end()) { - breaks_tws_map[id] = std::vector(); - } - breaks_tws_map[id].push_back(break_tw); - } - std::vector < vroom::Break > v_breaks; - for (auto v_break : breaks) { - v_breaks.push_back(get_vroom_break(v_break, breaks_tws_map[v_break.id])); - } - return v_breaks; - } - ///@} - - - /** - * @name vroom vehicles wrapper - */ - ///@{ - /** - * @brief Gets the vroom vehicles. - * - * @param[in] vehicle The vehicle C-style struct - * @param[in] breaks_tws The breaks time windows - * - * @return The vroom vehicle. - */ - vroom::Vehicle get_vroom_vehicle( - const Vroom_vehicle_t &vehicle, - const std::vector &breaks, - const std::vector &breaks_tws) const { - vroom::Amount capacity = - get_vroom_amounts(vehicle.capacity, vehicle.capacity_size); - vroom::Skills skills = - get_vroom_skills(vehicle.skills, vehicle.skills_size); - vroom::TimeWindow time_window = - get_vroom_time_window(vehicle.tw_open, - vehicle.tw_close); - std::vector v_breaks = get_vroom_breaks(breaks, breaks_tws); - - std::optional start_id; - std::optional end_id; - // Set the value of start or end index only if they are present - if (vehicle.start_id != -1) { - start_id = static_cast(m_matrix.get_index(vehicle.start_id)); - } - if (vehicle.end_id != -1) { - end_id = static_cast(m_matrix.get_index(vehicle.end_id)); - } - return vroom::Vehicle(vehicle.id, start_id, end_id, - vroom::DEFAULT_PROFILE, capacity, skills, time_window, - v_breaks, vehicle.data, vehicle.speed_factor, - static_cast(vehicle.max_tasks)); - } - - void problem_add_vehicle( - const Vroom_vehicle_t &vehicle, - const std::vector &breaks, - const std::vector &breaks_tws) { - m_vehicles.push_back(get_vroom_vehicle(vehicle, breaks, breaks_tws)); - } - - void add_vehicles(const std::vector &vehicles, - const std::vector &breaks, - const std::vector &breaks_tws) { - std::map> breaks_tws_map; - for (auto break_tw : breaks_tws) { - Idx id = break_tw.id; - if (breaks_tws_map.find(id) == breaks_tws_map.end()) { - breaks_tws_map[id] = std::vector(); - } - breaks_tws_map[id].push_back(break_tw); - } - - std::map> v_breaks_map; - for (auto v_break : breaks) { - Idx v_id = v_break.vehicle_id; - if (v_breaks_map.find(v_id) == v_breaks_map.end()) { - v_breaks_map[v_id] = std::vector(); - } - v_breaks_map[v_id].push_back(v_break); - } - - for (auto vehicle : vehicles) { - std::vector v_breaks = v_breaks_map[vehicle.id]; - std::vector v_breaks_tws; - for (auto v_break : v_breaks) { - std::vector tws = breaks_tws_map[v_break.id]; - v_breaks_tws.insert(v_breaks_tws.end(), tws.begin(), tws.end()); - } - problem_add_vehicle(vehicle, v_breaks, v_breaks_tws); - } - } - - void add_vehicles(const Vroom_vehicle_t *vehicles, size_t count, - const Vroom_break_t *breaks, size_t total_breaks, - const Vroom_time_window_t *breaks_tws, size_t total_breaks_tws) { - add_vehicles(std::vector(vehicles, vehicles + count), + std::vector jobs() const { return m_jobs; } + std::vector> shipments() const { return m_shipments; } + std::vector vehicles() const { return m_vehicles; } + vrprouting::base::Base_Matrix matrix() const { return m_matrix; } + + /** + * @name vroom time window wrapper + */ + ///@{ + /** + * @brief Gets the vroom time window from the C-style struct + * + * @param[in] time_window The C-style time window struct + * + * @return The vroom time window. + */ + vroom::TimeWindow + get_vroom_time_window(const Vroom_time_window_t &time_window) const { + return + vroom::TimeWindow(time_window.tw_open, + time_window.tw_close); + } + + vroom::TimeWindow + get_vroom_time_window(Duration tw_open, Duration tw_close) const { + return vroom::TimeWindow(tw_open, tw_close); + } + + std::vector + get_vroom_time_windows( + const std::vector &time_windows) const { + std::vector < vroom::TimeWindow > tws; + for (auto time_window : time_windows) { + tws.push_back(get_vroom_time_window(time_window)); + } + if (tws.size()) { + return tws; + } else { + return std::vector(1, vroom::TimeWindow()); + } + } + ///@} + + + /** + * @name vroom amounts wrapper + */ + ///@{ + /** + * @brief Gets the vroom amounts from C-style array + * + * @param[in] amounts The amounts array (pickup or delivery) + * + * @return The vroom amounts. + */ + vroom::Amount + get_vroom_amounts(const std::vector &amounts) const { + vroom::Amount amt; + if (amounts.size()) { + for (auto amount : amounts) { + amt.push_back(amount); + } + } else { + const unsigned int amount_size = + m_vehicles.size() ? static_cast(m_vehicles[0].capacity.size()) : 0; + // Default to zero amount with provided size. + amt = vroom::Amount(amount_size); + for (size_t i = 0; i < amounts.size(); i++) { + amt[i] = amounts[i]; + } + } + return amt; + } + + vroom::Amount + get_vroom_amounts(const Amount *amounts, size_t count) const { + return get_vroom_amounts(std::vector (amounts, amounts + count)); + } + ///@} + + + /** + * @name vroom skills wrapper + */ + ///@{ + /** + * @brief Gets the vroom skills. + * + * @param[in] skills The skills array + * @param[in] count The size of skills array + * + * @return The vroom skills. + */ + vroom::Skills + get_vroom_skills(const Skill *skills, size_t count) const { + return std::unordered_set (skills, skills + count); + } + ///@} + + + /** + * @name vroom jobs wrapper + */ + ///@{ + /** + * @brief Gets the vroom jobs. + * + * @param[in] job The job C-style struct + * @param[in] job_tws The job time windows + * + * @return The vroom job. + */ + vroom::Job + get_vroom_job(const Vroom_job_t &job, + const std::vector &job_tws) const { + vroom::Amount delivery = + get_vroom_amounts(job.delivery, job.delivery_size); + vroom::Amount pickup = + get_vroom_amounts(job.pickup, job.pickup_size); + vroom::Skills skills = + get_vroom_skills(job.skills, job.skills_size); + std::vector time_windows = + get_vroom_time_windows(job_tws); + vroom::Index location_id = + static_cast(m_matrix.get_index(job.location_id)); + return vroom::Job(job.id, location_id, job.setup, job.service, delivery, pickup, + skills, job.priority, time_windows, job.data); + } + + void problem_add_job(const Vroom_job_t &job, + const std::vector &job_tws) { + m_jobs.push_back(get_vroom_job(job, job_tws)); + } + + void add_jobs(const std::vector &jobs, + const std::vector &jobs_tws) { + std::map> job_tws_map; + for (auto job_tw : jobs_tws) { + Idx id = job_tw.id; + if (job_tws_map.find(id) == job_tws_map.end()) { + job_tws_map[id] = std::vector(); + } + job_tws_map[id].push_back(job_tw); + } + for (auto job : jobs) { + problem_add_job(job, job_tws_map[job.id]); + } + } + + void add_jobs(const Vroom_job_t *jobs, size_t count, + const Vroom_time_window_t *jobs_tws, size_t total_jobs_tws) { + add_jobs( + std::vector(jobs, jobs + count), + std::vector(jobs_tws, jobs_tws + total_jobs_tws)); + } + ///@} + + + /** + * @name vroom shipments wrapper + */ + ///@{ + /** + * @brief Gets the vroom shipments. + * + * @param[in] shipment The shipment C-style struct + * @param[in] pickup_tws The pickup time windows + * @param[in] delivery_tws The delivery time windows + * + * @return The vroom shipment. + */ + std::pair get_vroom_shipment( + const Vroom_shipment_t &shipment, + const std::vector &pickup_tws, + const std::vector &delivery_tws) const { + vroom::Amount amount = + get_vroom_amounts(shipment.amount, shipment.amount_size); + vroom::Skills skills = + get_vroom_skills(shipment.skills, shipment.skills_size); + std::vector p_time_windows = + get_vroom_time_windows(pickup_tws); + std::vector d_time_windows = + get_vroom_time_windows(delivery_tws); + vroom::Index p_location_id = static_cast( + m_matrix.get_index(shipment.p_location_id)); + vroom::Index d_location_id = static_cast( + m_matrix.get_index(shipment.d_location_id)); + vroom::Job pickup = vroom::Job( + shipment.id, vroom::JOB_TYPE::PICKUP, p_location_id, + shipment.p_setup, shipment.p_service, amount, + skills, shipment.priority, p_time_windows, shipment.p_data); + vroom::Job delivery = vroom::Job( + shipment.id, vroom::JOB_TYPE::DELIVERY, d_location_id, + shipment.d_setup, shipment.d_service, amount, + skills, shipment.priority, d_time_windows, shipment.d_data); + return std::make_pair(pickup, delivery); + } + + void problem_add_shipment( + const Vroom_shipment_t &shipment, + const std::vector &pickup_tws, + const std::vector &delivery_tws) { + m_shipments.push_back( + get_vroom_shipment(shipment, pickup_tws, delivery_tws)); + } + + void add_shipments(const std::vector &shipments, + const std::vector &shipments_tws) { + std::map> pickup_tws_map; + std::map> delivery_tws_map; + for (auto shipment_tw : shipments_tws) { + Idx id = shipment_tw.id; + if (shipment_tw.kind == 'p') { + if (pickup_tws_map.find(id) == pickup_tws_map.end()) { + pickup_tws_map[id] = std::vector(); + } + pickup_tws_map[id].push_back(shipment_tw); + } else if (shipment_tw.kind == 'd') { + if (delivery_tws_map.find(id) == delivery_tws_map.end()) { + delivery_tws_map[id] = std::vector(); + } + delivery_tws_map[id].push_back(shipment_tw); + } + } + for (auto shipment : shipments) { + problem_add_shipment(shipment, pickup_tws_map[shipment.id], + delivery_tws_map[shipment.id]); + } + } + + void add_shipments(const Vroom_shipment_t *shipments, size_t count, + const Vroom_time_window_t *shipment_tws, size_t total_shipment_tws) { + add_shipments( + std::vector(shipments, shipments + count), + std::vector(shipment_tws, shipment_tws + total_shipment_tws)); + } + ///@} + + + /** + * @name vroom breaks wrapper + */ + ///@{ + /** + * @brief Gets the vehicle breaks from C-style breaks struct + * + * @param[in] v_break The vehicle break struct + * + * @return The vroom vehicle break. + */ + vroom::Break + get_vroom_break( + const Vroom_break_t &v_break, + const std::vector &break_tws) const { + std::vector tws = get_vroom_time_windows(break_tws); + return vroom::Break(v_break.id, tws, v_break.service, v_break.data); + } + + std::vector < vroom::Break > + get_vroom_breaks( + const std::vector &breaks, + const std::vector &breaks_tws) const { + std::map> breaks_tws_map; + for (auto break_tw : breaks_tws) { + Idx id = break_tw.id; + if (breaks_tws_map.find(id) == breaks_tws_map.end()) { + breaks_tws_map[id] = std::vector(); + } + breaks_tws_map[id].push_back(break_tw); + } + std::vector < vroom::Break > v_breaks; + for (auto v_break : breaks) { + v_breaks.push_back(get_vroom_break(v_break, breaks_tws_map[v_break.id])); + } + return v_breaks; + } + ///@} + + + /** + * @name vroom vehicles wrapper + */ + ///@{ + /** + * @brief Gets the vroom vehicles. + * + * @param[in] vehicle The vehicle C-style struct + * @param[in] breaks_tws The breaks time windows + * + * @return The vroom vehicle. + */ + vroom::Vehicle get_vroom_vehicle( + const Vroom_vehicle_t &vehicle, + const std::vector &breaks, + const std::vector &breaks_tws) const { + vroom::Amount capacity = + get_vroom_amounts(vehicle.capacity, vehicle.capacity_size); + vroom::Skills skills = + get_vroom_skills(vehicle.skills, vehicle.skills_size); + vroom::TimeWindow time_window = + get_vroom_time_window(vehicle.tw_open, + vehicle.tw_close); + std::vector v_breaks = get_vroom_breaks(breaks, breaks_tws); + + std::optional start_id; + std::optional end_id; + // Set the value of start or end index only if they are present + if (vehicle.start_id != -1) { + start_id = static_cast(m_matrix.get_index(vehicle.start_id)); + } + if (vehicle.end_id != -1) { + end_id = static_cast(m_matrix.get_index(vehicle.end_id)); + } + return vroom::Vehicle(vehicle.id, start_id, end_id, + vroom::DEFAULT_PROFILE, capacity, skills, time_window, + v_breaks, vehicle.data, vehicle.speed_factor, + static_cast(vehicle.max_tasks)); + } + + void problem_add_vehicle( + const Vroom_vehicle_t &vehicle, + const std::vector &breaks, + const std::vector &breaks_tws) { + m_vehicles.push_back(get_vroom_vehicle(vehicle, breaks, breaks_tws)); + } + + void add_vehicles(const std::vector &vehicles, + const std::vector &breaks, + const std::vector &breaks_tws) { + std::map> breaks_tws_map; + for (auto break_tw : breaks_tws) { + Idx id = break_tw.id; + if (breaks_tws_map.find(id) == breaks_tws_map.end()) { + breaks_tws_map[id] = std::vector(); + } + breaks_tws_map[id].push_back(break_tw); + } + + std::map> v_breaks_map; + for (auto v_break : breaks) { + Idx v_id = v_break.vehicle_id; + if (v_breaks_map.find(v_id) == v_breaks_map.end()) { + v_breaks_map[v_id] = std::vector(); + } + v_breaks_map[v_id].push_back(v_break); + } + + for (auto vehicle : vehicles) { + std::vector v_breaks = v_breaks_map[vehicle.id]; + std::vector v_breaks_tws; + for (auto v_break : v_breaks) { + std::vector tws = breaks_tws_map[v_break.id]; + v_breaks_tws.insert(v_breaks_tws.end(), tws.begin(), tws.end()); + } + problem_add_vehicle(vehicle, v_breaks, v_breaks_tws); + } + } + + void add_vehicles(const Vroom_vehicle_t *vehicles, size_t count, + const Vroom_break_t *breaks, size_t total_breaks, + const Vroom_time_window_t *breaks_tws, size_t total_breaks_tws) { + add_vehicles(std::vector(vehicles, vehicles + count), std::vector(breaks, breaks + total_breaks), std::vector(breaks_tws, breaks_tws + total_breaks_tws)); - } - ///@} - - - void add_matrix(vrprouting::base::Base_Matrix matrix) { - m_matrix = matrix; - } - - void get_amount(vroom::Amount vroom_amount, Amount **amount) { - size_t amount_size = vroom_amount.size(); - for (size_t i = 0; i < amount_size; i++) { - *((*amount) + i) = vroom_amount[i]; - } - } - - StepType get_job_step_type(vroom::JOB_TYPE vroom_job_type) { - StepType step_type; - switch (vroom_job_type) { - case vroom::JOB_TYPE::SINGLE: - step_type = 2; - break; - case vroom::JOB_TYPE::PICKUP: - step_type = 3; - break; - case vroom::JOB_TYPE::DELIVERY: - step_type = 4; - break; - } - return step_type; - } - - StepType get_step_type(vroom::Step step) { - StepType step_type = 0; - switch (step.step_type) { - case vroom::STEP_TYPE::START: - step_type = 1; - break; - case vroom::STEP_TYPE::END: - step_type = 6; - break; - case vroom::STEP_TYPE::BREAK: - step_type = 5; - break; - case vroom::STEP_TYPE::JOB: - step_type = get_job_step_type(step.job_type); - break; - } - return step_type; - } - - std::vector < Vroom_rt > get_results(vroom::Solution solution) { - std::vector < Vroom_rt > results; - std::vector routes = solution.routes; - Idx vehicle_seq = 1; - char *empty_desc = strdup("{}"); - for (auto route : routes) { - Idx step_seq = 1; - Duration prev_duration = 0; - char *vehicle_data = strdup(route.description.c_str()); - for (auto step : route.steps) { - Idx task_id = step.id; - MatrixIndex location_id = m_matrix.get_original_id(step.location.index()); - char *task_data = strdup(step.description.c_str()); - StepType step_type = get_step_type(step); - if (step_type == 1 || step_type == 6) { - task_id = static_cast(-1); - task_data = empty_desc; - } - - size_t load_size = step.load.size(); - Amount *load = reinterpret_cast(malloc(load_size * sizeof(Amount))); - get_amount(step.load, &load); - - Duration travel_time = step.duration - prev_duration; - prev_duration = step.duration; - Duration departure = step.arrival + step.setup + step.service + step.waiting_time; - results.push_back({ - vehicle_seq, // vehicles_seq - route.vehicle, // vehicles_id - vehicle_data, // vehicle_data - step_seq, // step_seq - step_type, // step_type - task_id, // task_id - location_id, // location_id - task_data, // task_data - step.arrival, // arrival - travel_time, // travel_time - step.setup, // setup_time - step.service, // service_time - step.waiting_time, // waiting_time - departure, // departure - load, // load - load_size // load size - }); - step_seq++; - } - // The summary of this route - Idx task_id = 0; - results.push_back({ - vehicle_seq, // vehicles_seq - route.vehicle, // vehicles_id - vehicle_data, // vehicle_data - 0, // step_seq = 0 for route summary - 0, // step_type = 0 for route summary - task_id, // task_id = 0 for route summary - 0, // location_id = 0 for route summary - empty_desc, // task_data - 0, // No arrival time - route.duration, // Total travel time - route.setup, // Total setup time - route.service, // Total service time - route.waiting_time, // Total waiting time - 0, // No departure time - {}, // load - 0 // load size - }); - vehicle_seq++; - } - - std::vector unassigned = solution.unassigned; - Idx step_seq = 1; - for (auto job : unassigned) { - StepType job_step = get_job_step_type(job.type); - Idx vehicle_id = static_cast(-1); - Idx job_id = job.id; - MatrixIndex location_id = m_matrix.get_original_id(job.location.index()); - char *task_data = strdup(job.description.c_str()); - results.push_back({ - vehicle_seq, // vehicles_seq - vehicle_id, // vehicles_id = -1 for unassigned jobs - empty_desc, // vehicle_data - step_seq, // step_seq - job_step, // step_type - job_id, // task_id - location_id, // location_id - task_data, // task_data - 0, // No arrival time - 0, // No travel_time - 0, // No setup_time - 0, // No service_time - 0, // No waiting_time - 0, // No departure time - {}, // load - 0 // load size - }); - step_seq++; - } - - // The summary of the entire problem - vroom::Summary summary = solution.summary; - Idx vehicle_id = 0; - Idx job_id = 0; - results.push_back({ - 0, // vehicles_seq = 0 for problem summary - vehicle_id, // vehicles_id = 0 for problem summary - empty_desc, // vehicle_data - 0, // step_seq = 0 for problem summary - 0, // step_type = 0 for problem summary - job_id, // task_id = 0 for problem summary - 0, // location_id = 0 for problem summary - empty_desc, // task_data - 0, // No arrival time - summary.duration, // Total travel time - summary.setup, // Total setup time - summary.service, // Total service time - summary.waiting_time, // Total waiting time - 0, // No departure time - {}, // load - 0 // load size - }); - return results; - } - - std::vector solve(int32_t exploration_level, int32_t timeout, - int32_t loading_time) { - std::vector results; - - /* abort in case an interruption occurs (e.g. the query is being cancelled) */ - CHECK_FOR_INTERRUPTS(); - try { - const unsigned int amount_size = - m_vehicles.size() - ? static_cast(m_vehicles[0].capacity.size()) - : 0; - vroom::Input problem_instance; - problem_instance.set_amount_size(amount_size); - - for (const auto &vehicle : m_vehicles) { - problem_instance.add_vehicle(vehicle); - } - for (const auto &job : m_jobs) { - problem_instance.add_job(job); - } - for (const auto &shipment : m_shipments) { - problem_instance.add_shipment(shipment.first, shipment.second); - } - vroom::Matrix duration_matrix = m_matrix.get_vroom_duration_matrix(); - vroom::Matrix cost_matrix = m_matrix.get_vroom_cost_matrix(); - problem_instance.set_durations_matrix(vroom::DEFAULT_PROFILE, std::move(duration_matrix)); - problem_instance.set_costs_matrix(vroom::DEFAULT_PROFILE, std::move(cost_matrix)); - - unsigned threads = 4; - if (timeout < 0) { - auto solution = problem_instance.solve( - static_cast(exploration_level), threads); - results = get_results(solution); - } else { - int timeout_ms = (loading_time <= timeout * 1000) ? (timeout * 1000 - loading_time) : 0; - auto solution = problem_instance.solve( - static_cast(exploration_level), threads, timeout_ms); - results = get_results(solution); - } - } catch (const vroom::Exception &ex) { - throw; - } catch (const std::exception &ex) { - throw; - } catch (...) { - throw; - } - return results; - } + } + ///@} + + + void add_matrix(vrprouting::base::Base_Matrix matrix) { + m_matrix = matrix; + } + + void get_amount(vroom::Amount vroom_amount, Amount **amount) { + size_t amount_size = vroom_amount.size(); + for (size_t i = 0; i < amount_size; i++) { + *((*amount) + i) = vroom_amount[i]; + } + } + + StepType get_job_step_type(vroom::JOB_TYPE vroom_job_type) { + StepType step_type; + switch (vroom_job_type) { + case vroom::JOB_TYPE::SINGLE: + step_type = 2; + break; + case vroom::JOB_TYPE::PICKUP: + step_type = 3; + break; + case vroom::JOB_TYPE::DELIVERY: + step_type = 4; + break; + } + return step_type; + } + + StepType get_step_type(vroom::Step step) { + StepType step_type = 0; + switch (step.step_type) { + case vroom::STEP_TYPE::START: + step_type = 1; + break; + case vroom::STEP_TYPE::END: + step_type = 6; + break; + case vroom::STEP_TYPE::BREAK: + step_type = 5; + break; + case vroom::STEP_TYPE::JOB: + step_type = get_job_step_type(step.job_type); + break; + } + return step_type; + } + + std::vector < Vroom_rt > get_results(vroom::Solution solution) { + std::vector < Vroom_rt > results; + std::vector routes = solution.routes; + Idx vehicle_seq = 1; + char *empty_desc = strdup("{}"); + for (auto route : routes) { + Idx step_seq = 1; + Duration prev_duration = 0; + char *vehicle_data = strdup(route.description.c_str()); + for (auto step : route.steps) { + Idx task_id = step.id; + MatrixIndex location_id = m_matrix.get_original_id(step.location.index()); + char *task_data = strdup(step.description.c_str()); + StepType step_type = get_step_type(step); + if (step_type == 1 || step_type == 6) { + task_id = static_cast(-1); + task_data = empty_desc; + } + + size_t load_size = step.load.size(); + Amount *load = reinterpret_cast(malloc(load_size * sizeof(Amount))); + get_amount(step.load, &load); + + Duration travel_time = step.duration - prev_duration; + prev_duration = step.duration; + Duration departure = step.arrival + step.setup + step.service + step.waiting_time; + results.push_back({ + vehicle_seq, // vehicles_seq + route.vehicle, // vehicles_id + vehicle_data, // vehicle_data + step_seq, // step_seq + step_type, // step_type + task_id, // task_id + location_id, // location_id + task_data, // task_data + step.arrival, // arrival + travel_time, // travel_time + step.setup, // setup_time + step.service, // service_time + step.waiting_time, // waiting_time + departure, // departure + load, // load + load_size // load size + }); + step_seq++; + } + // The summary of this route + Idx task_id = 0; + results.push_back({ + vehicle_seq, // vehicles_seq + route.vehicle, // vehicles_id + vehicle_data, // vehicle_data + 0, // step_seq = 0 for route summary + 0, // step_type = 0 for route summary + task_id, // task_id = 0 for route summary + 0, // location_id = 0 for route summary + empty_desc, // task_data + 0, // No arrival time + route.duration, // Total travel time + route.setup, // Total setup time + route.service, // Total service time + route.waiting_time, // Total waiting time + 0, // No departure time + {}, // load + 0 // load size + }); + vehicle_seq++; + } + + std::vector unassigned = solution.unassigned; + Idx step_seq = 1; + for (auto job : unassigned) { + StepType job_step = get_job_step_type(job.type); + Idx vehicle_id = static_cast(-1); + Idx job_id = job.id; + MatrixIndex location_id = m_matrix.get_original_id(job.location.index()); + char *task_data = strdup(job.description.c_str()); + results.push_back({ + vehicle_seq, // vehicles_seq + vehicle_id, // vehicles_id = -1 for unassigned jobs + empty_desc, // vehicle_data + step_seq, // step_seq + job_step, // step_type + job_id, // task_id + location_id, // location_id + task_data, // task_data + 0, // No arrival time + 0, // No travel_time + 0, // No setup_time + 0, // No service_time + 0, // No waiting_time + 0, // No departure time + {}, // load + 0 // load size + }); + step_seq++; + } + + // The summary of the entire problem + vroom::Summary summary = solution.summary; + Idx vehicle_id = 0; + Idx job_id = 0; + results.push_back({ + 0, // vehicles_seq = 0 for problem summary + vehicle_id, // vehicles_id = 0 for problem summary + empty_desc, // vehicle_data + 0, // step_seq = 0 for problem summary + 0, // step_type = 0 for problem summary + job_id, // task_id = 0 for problem summary + 0, // location_id = 0 for problem summary + empty_desc, // task_data + 0, // No arrival time + summary.duration, // Total travel time + summary.setup, // Total setup time + summary.service, // Total service time + summary.waiting_time, // Total waiting time + 0, // No departure time + {}, // load + 0 // load size + }); + return results; + } + + std::vector solve(int32_t exploration_level, int32_t timeout, + int32_t loading_time) { + std::vector results; + + /* abort in case an interruption occurs (e.g. the query is being cancelled) */ + CHECK_FOR_INTERRUPTS(); + try { + const unsigned int amount_size = + m_vehicles.size() + ? static_cast(m_vehicles[0].capacity.size()) + : 0; + vroom::Input problem_instance; + problem_instance.set_amount_size(amount_size); + + for (const auto &vehicle : m_vehicles) { + problem_instance.add_vehicle(vehicle); + } + for (const auto &job : m_jobs) { + problem_instance.add_job(job); + } + for (const auto &shipment : m_shipments) { + problem_instance.add_shipment(shipment.first, shipment.second); + } + vroom::Matrix duration_matrix = m_matrix.get_vroom_duration_matrix(); + vroom::Matrix cost_matrix = m_matrix.get_vroom_cost_matrix(); + problem_instance.set_durations_matrix(vroom::DEFAULT_PROFILE, std::move(duration_matrix)); + problem_instance.set_costs_matrix(vroom::DEFAULT_PROFILE, std::move(cost_matrix)); + + unsigned threads = 4; + if (timeout < 0) { + auto solution = problem_instance.solve( + static_cast(exploration_level), threads); + results = get_results(solution); + } else { + int timeout_ms = (loading_time <= timeout * 1000) ? (timeout * 1000 - loading_time) : 0; + auto solution = problem_instance.solve( + static_cast(exploration_level), threads, timeout_ms); + results = get_results(solution); + } + } catch (const vroom::Exception &ex) { + throw; + } catch (const std::exception &ex) { + throw; + } catch (...) { + throw; + } + return results; + } private: - std::vector m_jobs; - std::vector> m_shipments; - std::vector m_vehicles; - vrprouting::base::Base_Matrix m_matrix; + std::vector m_jobs; + std::vector> m_shipments; + std::vector m_vehicles; + vrprouting::base::Base_Matrix m_matrix; }; } // namespace vrprouting diff --git a/locale/en/LC_MESSAGES/release_notes.po b/locale/en/LC_MESSAGES/release_notes.po index 9b2df9da8..39145805a 100644 --- a/locale/en/LC_MESSAGES/release_notes.po +++ b/locale/en/LC_MESSAGES/release_notes.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: vrpRouting v0.0.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-04 15:19+0000\n" +"POT-Creation-Date: 2024-08-06 20:01+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -85,23 +85,27 @@ msgstr "" msgid "Moved sphinx doc from .c files .rst files" msgstr "" -#: ../../build/doc/release_notes.rst:55 -msgid "Documentation queries" +#: ../../build/doc/release_notes.rst:52 +msgid "removing prefix `pgr_` & addding `namespace vrprouting`" msgstr "" #: ../../build/doc/release_notes.rst:56 -msgid "Renamed to extension `.pg`" +msgid "Documentation queries" msgstr "" #: ../../build/doc/release_notes.rst:57 +msgid "Renamed to extension `.pg`" +msgstr "" + +#: ../../build/doc/release_notes.rst:58 msgid "Removed `doc-` and `doc-vrp_` suffixes on file names" msgstr "" -#: ../../build/doc/release_notes.rst:60 +#: ../../build/doc/release_notes.rst:61 msgid "vrpRouting 0.4.1 Release Notes" msgstr "" -#: ../../build/doc/release_notes.rst:62 +#: ../../build/doc/release_notes.rst:63 #, python-format msgid "" "To see all issues & pull requests closed by this release see the `Git " @@ -110,23 +114,23 @@ msgid "" " on Github." msgstr "" -#: ../../build/doc/release_notes.rst:68 +#: ../../build/doc/release_notes.rst:69 msgid "Modification on experimental functions" msgstr "" -#: ../../build/doc/release_notes.rst:69 +#: ../../build/doc/release_notes.rst:70 msgid "OR Tools" msgstr "" -#: ../../build/doc/release_notes.rst:71 +#: ../../build/doc/release_notes.rst:72 msgid "vrp_bin_packing" msgstr "" -#: ../../build/doc/release_notes.rst:72 +#: ../../build/doc/release_notes.rst:73 msgid "vrp_knapsack" msgstr "" -#: ../../build/doc/release_notes.rst:73 +#: ../../build/doc/release_notes.rst:74 msgid "vrp_multiple_knapsack" msgstr "" @@ -134,7 +138,7 @@ msgstr "" msgid "Support for or-tools v9.10.4067" msgstr "" -#: ../../build/doc/release_notes.rst:79 +#: ../../build/doc/release_notes.rst:80 msgid "vrp_oneDepot" msgstr "" @@ -146,15 +150,15 @@ msgstr "" msgid "Result columns changed" msgstr "" -#: ../../build/doc/release_notes.rst:86 +#: ../../build/doc/release_notes.rst:87 msgid "Removal of Boost on the build" msgstr "" -#: ../../build/doc/release_notes.rst:87 ../../build/doc/release_notes.rst:185 +#: ../../build/doc/release_notes.rst:88 ../../build/doc/release_notes.rst:186 msgid "vrp_full_version" msgstr "" -#: ../../build/doc/release_notes.rst:88 ../../build/doc/release_notes.rst:184 +#: ../../build/doc/release_notes.rst:89 ../../build/doc/release_notes.rst:185 msgid "vrp_version" msgstr "" @@ -162,11 +166,11 @@ msgstr "" msgid "Boost removed from the result columns" msgstr "" -#: ../../build/doc/release_notes.rst:95 +#: ../../build/doc/release_notes.rst:96 msgid "vrpRouting 0.4.0 Release Notes" msgstr "" -#: ../../build/doc/release_notes.rst:97 +#: ../../build/doc/release_notes.rst:98 #, python-format msgid "" "To see all issues & pull requests closed by this release see the `Git " @@ -175,39 +179,39 @@ msgid "" " on Github." msgstr "" -#: ../../build/doc/release_notes.rst:102 +#: ../../build/doc/release_notes.rst:103 msgid "" "Added support for VROOM 1.12.0 (`#34 " "`_)" msgstr "" -#: ../../build/doc/release_notes.rst:103 +#: ../../build/doc/release_notes.rst:104 msgid "No visible changes on user side with respect to signatures." msgstr "" -#: ../../build/doc/release_notes.rst:104 +#: ../../build/doc/release_notes.rst:105 msgid "Adjusted to VROOM v1.12.0 due to internal breaking changes:" msgstr "" -#: ../../build/doc/release_notes.rst:106 +#: ../../build/doc/release_notes.rst:107 msgid "Made changes according to new vroom::Input signature." msgstr "" -#: ../../build/doc/release_notes.rst:107 +#: ../../build/doc/release_notes.rst:108 msgid "" "CI changes to compile without routing support, with Position Independent " "Code." msgstr "" -#: ../../build/doc/release_notes.rst:108 +#: ../../build/doc/release_notes.rst:109 msgid "Removed support for VROOM 1.11.0" msgstr "" -#: ../../build/doc/release_notes.rst:111 +#: ../../build/doc/release_notes.rst:112 msgid "vrpRouting 0.3" msgstr "" -#: ../../build/doc/release_notes.rst:113 +#: ../../build/doc/release_notes.rst:114 #, python-format msgid "" "To see all issues & pull requests closed by this release see the `Git " @@ -216,87 +220,87 @@ msgid "" " on Github." msgstr "" -#: ../../build/doc/release_notes.rst:118 +#: ../../build/doc/release_notes.rst:119 msgid "Modification of experimental functions" msgstr "" -#: ../../build/doc/release_notes.rst:119 ../../build/doc/release_notes.rst:157 +#: ../../build/doc/release_notes.rst:120 ../../build/doc/release_notes.rst:158 msgid "VROOM" msgstr "" -#: ../../build/doc/release_notes.rst:121 ../../build/doc/release_notes.rst:159 +#: ../../build/doc/release_notes.rst:122 ../../build/doc/release_notes.rst:160 msgid "vrp_vroom" msgstr "" -#: ../../build/doc/release_notes.rst:122 ../../build/doc/release_notes.rst:160 +#: ../../build/doc/release_notes.rst:123 ../../build/doc/release_notes.rst:161 msgid "vrp_vroomJobs" msgstr "" -#: ../../build/doc/release_notes.rst:123 ../../build/doc/release_notes.rst:161 +#: ../../build/doc/release_notes.rst:124 ../../build/doc/release_notes.rst:162 msgid "vrp_vroomShipments" msgstr "" -#: ../../build/doc/release_notes.rst:124 ../../build/doc/release_notes.rst:162 +#: ../../build/doc/release_notes.rst:125 ../../build/doc/release_notes.rst:163 msgid "vrp_vroomPlain" msgstr "" -#: ../../build/doc/release_notes.rst:125 ../../build/doc/release_notes.rst:163 +#: ../../build/doc/release_notes.rst:126 ../../build/doc/release_notes.rst:164 msgid "vrp_vroomJobsPlain" msgstr "" -#: ../../build/doc/release_notes.rst:126 ../../build/doc/release_notes.rst:164 +#: ../../build/doc/release_notes.rst:127 ../../build/doc/release_notes.rst:165 msgid "vrp_vroomShipmentsPlain" msgstr "" -#: ../../build/doc/release_notes.rst:129 +#: ../../build/doc/release_notes.rst:130 msgid "" "Added support for VROOM 1.11.0 (`#24 " "`_)" msgstr "" -#: ../../build/doc/release_notes.rst:130 +#: ../../build/doc/release_notes.rst:131 msgid "Added setup time in jobs and shipments to refine service time modeling." msgstr "" -#: ../../build/doc/release_notes.rst:131 +#: ../../build/doc/release_notes.rst:132 msgid "Added support for custom cost matrices, along with the duration matrix." msgstr "" -#: ../../build/doc/release_notes.rst:133 +#: ../../build/doc/release_notes.rst:134 msgid "Using start_id, end_id, duration, cost as matrix table columns." msgstr "" -#: ../../build/doc/release_notes.rst:134 +#: ../../build/doc/release_notes.rst:135 msgid "" "Added timeout and exploration_level parameters to vroom-category " "functions." msgstr "" -#: ../../build/doc/release_notes.rst:135 +#: ../../build/doc/release_notes.rst:136 msgid "Added max_tasks column in vehicles." msgstr "" -#: ../../build/doc/release_notes.rst:136 +#: ../../build/doc/release_notes.rst:137 msgid "Added tests for empty skills arrays." msgstr "" -#: ../../build/doc/release_notes.rst:137 +#: ../../build/doc/release_notes.rst:138 msgid "Added custom scaling logic for speed_factor." msgstr "" -#: ../../build/doc/release_notes.rst:138 +#: ../../build/doc/release_notes.rst:139 msgid "Modified parameter names to make the naming consistent." msgstr "" -#: ../../build/doc/release_notes.rst:141 +#: ../../build/doc/release_notes.rst:142 msgid "Fixes" msgstr "" -#: ../../build/doc/release_notes.rst:142 +#: ../../build/doc/release_notes.rst:143 msgid "Honor client cancel requests for vroom-category functions." msgstr "" -#: ../../build/doc/release_notes.rst:143 +#: ../../build/doc/release_notes.rst:144 msgid "" "Added more information in the inner query and result columns of VROOM " "category functions (`#26 " @@ -304,79 +308,79 @@ msgid "" "`_):" msgstr "" -#: ../../build/doc/release_notes.rst:146 +#: ../../build/doc/release_notes.rst:147 msgid "Summary row in the output, for each vehicle and for the complete problem." msgstr "" -#: ../../build/doc/release_notes.rst:147 +#: ../../build/doc/release_notes.rst:148 msgid "Uassigned rows in the output with vehicle_id = -1." msgstr "" -#: ../../build/doc/release_notes.rst:148 +#: ../../build/doc/release_notes.rst:149 msgid "" "Modified travel_time result column to return travel time between current " "and last step." msgstr "" -#: ../../build/doc/release_notes.rst:149 +#: ../../build/doc/release_notes.rst:150 msgid "" "Added data jsonb field in jobs, shipments, vehicles, breaks as well as in" " the result columns." msgstr "" -#: ../../build/doc/release_notes.rst:150 +#: ../../build/doc/release_notes.rst:151 msgid "Added departure field and location_id field in the result columns." msgstr "" -#: ../../build/doc/release_notes.rst:153 +#: ../../build/doc/release_notes.rst:154 msgid "vrpRouting 0.2" msgstr "" -#: ../../build/doc/release_notes.rst:156 +#: ../../build/doc/release_notes.rst:157 msgid "New experimental functions" msgstr "" -#: ../../build/doc/release_notes.rst:166 +#: ../../build/doc/release_notes.rst:167 msgid "VRP" msgstr "" -#: ../../build/doc/release_notes.rst:168 +#: ../../build/doc/release_notes.rst:169 msgid "vrp_compatibleVehicles" msgstr "" -#: ../../build/doc/release_notes.rst:169 +#: ../../build/doc/release_notes.rst:170 msgid "vrp_optimize" msgstr "" -#: ../../build/doc/release_notes.rst:170 +#: ../../build/doc/release_notes.rst:171 msgid "vrp_pickDeliverAdd" msgstr "" -#: ../../build/doc/release_notes.rst:171 +#: ../../build/doc/release_notes.rst:172 msgid "vrp_pickDeliver" msgstr "" -#: ../../build/doc/release_notes.rst:172 +#: ../../build/doc/release_notes.rst:173 msgid "vrp_simulation" msgstr "" -#: ../../build/doc/release_notes.rst:173 +#: ../../build/doc/release_notes.rst:174 msgid "vrp_viewRoute" msgstr "" -#: ../../build/doc/release_notes.rst:176 +#: ../../build/doc/release_notes.rst:177 msgid "vrpRouting 0.1" msgstr "" -#: ../../build/doc/release_notes.rst:179 +#: ../../build/doc/release_notes.rst:180 msgid "Extraction tasks" msgstr "" -#: ../../build/doc/release_notes.rst:180 +#: ../../build/doc/release_notes.rst:181 msgid "Porting pgRouting's VRP functionality" msgstr "" -#: ../../build/doc/release_notes.rst:183 +#: ../../build/doc/release_notes.rst:184 msgid "New official functions" msgstr "" diff --git a/locale/pot/release_notes.pot b/locale/pot/release_notes.pot index 3cc152206..afb81e5c2 100644 --- a/locale/pot/release_notes.pot +++ b/locale/pot/release_notes.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: vrpRouting v0.4.2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-04 15:19+0000\n" +"POT-Creation-Date: 2024-08-06 20:01+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -72,43 +72,47 @@ msgstr "" msgid "Moved sphinx doc from .c files .rst files" msgstr "" -#: ../../build/doc/release_notes.rst:55 -msgid "Documentation queries" +#: ../../build/doc/release_notes.rst:52 +msgid "removing prefix `pgr_` & addding `namespace vrprouting`" msgstr "" #: ../../build/doc/release_notes.rst:56 -msgid "Renamed to extension `.pg`" +msgid "Documentation queries" msgstr "" #: ../../build/doc/release_notes.rst:57 +msgid "Renamed to extension `.pg`" +msgstr "" + +#: ../../build/doc/release_notes.rst:58 msgid "Removed `doc-` and `doc-vrp_` suffixes on file names" msgstr "" -#: ../../build/doc/release_notes.rst:60 +#: ../../build/doc/release_notes.rst:61 msgid "vrpRouting 0.4.1 Release Notes" msgstr "" -#: ../../build/doc/release_notes.rst:62 +#: ../../build/doc/release_notes.rst:63 msgid "To see all issues & pull requests closed by this release see the `Git closed milestone for 0.4.1 `_ on Github." msgstr "" -#: ../../build/doc/release_notes.rst:68 +#: ../../build/doc/release_notes.rst:69 msgid "Modification on experimental functions" msgstr "" -#: ../../build/doc/release_notes.rst:69 +#: ../../build/doc/release_notes.rst:70 msgid "OR Tools" msgstr "" -#: ../../build/doc/release_notes.rst:71 +#: ../../build/doc/release_notes.rst:72 msgid "vrp_bin_packing" msgstr "" -#: ../../build/doc/release_notes.rst:72 +#: ../../build/doc/release_notes.rst:73 msgid "vrp_knapsack" msgstr "" -#: ../../build/doc/release_notes.rst:73 +#: ../../build/doc/release_notes.rst:74 msgid "vrp_multiple_knapsack" msgstr "" @@ -116,7 +120,7 @@ msgstr "" msgid "Support for or-tools v9.10.4067" msgstr "" -#: ../../build/doc/release_notes.rst:79 +#: ../../build/doc/release_notes.rst:80 msgid "vrp_oneDepot" msgstr "" @@ -128,17 +132,17 @@ msgstr "" msgid "Result columns changed" msgstr "" -#: ../../build/doc/release_notes.rst:86 +#: ../../build/doc/release_notes.rst:87 msgid "Removal of Boost on the build" msgstr "" -#: ../../build/doc/release_notes.rst:87 -#: ../../build/doc/release_notes.rst:185 +#: ../../build/doc/release_notes.rst:88 +#: ../../build/doc/release_notes.rst:186 msgid "vrp_full_version" msgstr "" -#: ../../build/doc/release_notes.rst:88 -#: ../../build/doc/release_notes.rst:184 +#: ../../build/doc/release_notes.rst:89 +#: ../../build/doc/release_notes.rst:185 msgid "vrp_version" msgstr "" @@ -146,201 +150,201 @@ msgstr "" msgid "Boost removed from the result columns" msgstr "" -#: ../../build/doc/release_notes.rst:95 +#: ../../build/doc/release_notes.rst:96 msgid "vrpRouting 0.4.0 Release Notes" msgstr "" -#: ../../build/doc/release_notes.rst:97 +#: ../../build/doc/release_notes.rst:98 msgid "To see all issues & pull requests closed by this release see the `Git closed milestone for 0.4.0 `_ on Github." msgstr "" -#: ../../build/doc/release_notes.rst:102 +#: ../../build/doc/release_notes.rst:103 msgid "Added support for VROOM 1.12.0 (`#34 `_)" msgstr "" -#: ../../build/doc/release_notes.rst:103 +#: ../../build/doc/release_notes.rst:104 msgid "No visible changes on user side with respect to signatures." msgstr "" -#: ../../build/doc/release_notes.rst:104 +#: ../../build/doc/release_notes.rst:105 msgid "Adjusted to VROOM v1.12.0 due to internal breaking changes:" msgstr "" -#: ../../build/doc/release_notes.rst:106 +#: ../../build/doc/release_notes.rst:107 msgid "Made changes according to new vroom::Input signature." msgstr "" -#: ../../build/doc/release_notes.rst:107 +#: ../../build/doc/release_notes.rst:108 msgid "CI changes to compile without routing support, with Position Independent Code." msgstr "" -#: ../../build/doc/release_notes.rst:108 +#: ../../build/doc/release_notes.rst:109 msgid "Removed support for VROOM 1.11.0" msgstr "" -#: ../../build/doc/release_notes.rst:111 +#: ../../build/doc/release_notes.rst:112 msgid "vrpRouting 0.3" msgstr "" -#: ../../build/doc/release_notes.rst:113 +#: ../../build/doc/release_notes.rst:114 msgid "To see all issues & pull requests closed by this release see the `Git closed milestone for 0.3.0 `_ on Github." msgstr "" -#: ../../build/doc/release_notes.rst:118 +#: ../../build/doc/release_notes.rst:119 msgid "Modification of experimental functions" msgstr "" -#: ../../build/doc/release_notes.rst:119 -#: ../../build/doc/release_notes.rst:157 +#: ../../build/doc/release_notes.rst:120 +#: ../../build/doc/release_notes.rst:158 msgid "VROOM" msgstr "" -#: ../../build/doc/release_notes.rst:121 -#: ../../build/doc/release_notes.rst:159 -msgid "vrp_vroom" -msgstr "" - #: ../../build/doc/release_notes.rst:122 #: ../../build/doc/release_notes.rst:160 -msgid "vrp_vroomJobs" +msgid "vrp_vroom" msgstr "" #: ../../build/doc/release_notes.rst:123 #: ../../build/doc/release_notes.rst:161 -msgid "vrp_vroomShipments" +msgid "vrp_vroomJobs" msgstr "" #: ../../build/doc/release_notes.rst:124 #: ../../build/doc/release_notes.rst:162 -msgid "vrp_vroomPlain" +msgid "vrp_vroomShipments" msgstr "" #: ../../build/doc/release_notes.rst:125 #: ../../build/doc/release_notes.rst:163 -msgid "vrp_vroomJobsPlain" +msgid "vrp_vroomPlain" msgstr "" #: ../../build/doc/release_notes.rst:126 #: ../../build/doc/release_notes.rst:164 +msgid "vrp_vroomJobsPlain" +msgstr "" + +#: ../../build/doc/release_notes.rst:127 +#: ../../build/doc/release_notes.rst:165 msgid "vrp_vroomShipmentsPlain" msgstr "" -#: ../../build/doc/release_notes.rst:129 +#: ../../build/doc/release_notes.rst:130 msgid "Added support for VROOM 1.11.0 (`#24 `_)" msgstr "" -#: ../../build/doc/release_notes.rst:130 +#: ../../build/doc/release_notes.rst:131 msgid "Added setup time in jobs and shipments to refine service time modeling." msgstr "" -#: ../../build/doc/release_notes.rst:131 +#: ../../build/doc/release_notes.rst:132 msgid "Added support for custom cost matrices, along with the duration matrix." msgstr "" -#: ../../build/doc/release_notes.rst:133 +#: ../../build/doc/release_notes.rst:134 msgid "Using start_id, end_id, duration, cost as matrix table columns." msgstr "" -#: ../../build/doc/release_notes.rst:134 +#: ../../build/doc/release_notes.rst:135 msgid "Added timeout and exploration_level parameters to vroom-category functions." msgstr "" -#: ../../build/doc/release_notes.rst:135 +#: ../../build/doc/release_notes.rst:136 msgid "Added max_tasks column in vehicles." msgstr "" -#: ../../build/doc/release_notes.rst:136 +#: ../../build/doc/release_notes.rst:137 msgid "Added tests for empty skills arrays." msgstr "" -#: ../../build/doc/release_notes.rst:137 +#: ../../build/doc/release_notes.rst:138 msgid "Added custom scaling logic for speed_factor." msgstr "" -#: ../../build/doc/release_notes.rst:138 +#: ../../build/doc/release_notes.rst:139 msgid "Modified parameter names to make the naming consistent." msgstr "" -#: ../../build/doc/release_notes.rst:141 +#: ../../build/doc/release_notes.rst:142 msgid "Fixes" msgstr "" -#: ../../build/doc/release_notes.rst:142 +#: ../../build/doc/release_notes.rst:143 msgid "Honor client cancel requests for vroom-category functions." msgstr "" -#: ../../build/doc/release_notes.rst:143 +#: ../../build/doc/release_notes.rst:144 msgid "Added more information in the inner query and result columns of VROOM category functions (`#26 `_, `#27 `_):" msgstr "" -#: ../../build/doc/release_notes.rst:146 +#: ../../build/doc/release_notes.rst:147 msgid "Summary row in the output, for each vehicle and for the complete problem." msgstr "" -#: ../../build/doc/release_notes.rst:147 +#: ../../build/doc/release_notes.rst:148 msgid "Uassigned rows in the output with vehicle_id = -1." msgstr "" -#: ../../build/doc/release_notes.rst:148 +#: ../../build/doc/release_notes.rst:149 msgid "Modified travel_time result column to return travel time between current and last step." msgstr "" -#: ../../build/doc/release_notes.rst:149 +#: ../../build/doc/release_notes.rst:150 msgid "Added data jsonb field in jobs, shipments, vehicles, breaks as well as in the result columns." msgstr "" -#: ../../build/doc/release_notes.rst:150 +#: ../../build/doc/release_notes.rst:151 msgid "Added departure field and location_id field in the result columns." msgstr "" -#: ../../build/doc/release_notes.rst:153 +#: ../../build/doc/release_notes.rst:154 msgid "vrpRouting 0.2" msgstr "" -#: ../../build/doc/release_notes.rst:156 +#: ../../build/doc/release_notes.rst:157 msgid "New experimental functions" msgstr "" -#: ../../build/doc/release_notes.rst:166 +#: ../../build/doc/release_notes.rst:167 msgid "VRP" msgstr "" -#: ../../build/doc/release_notes.rst:168 +#: ../../build/doc/release_notes.rst:169 msgid "vrp_compatibleVehicles" msgstr "" -#: ../../build/doc/release_notes.rst:169 +#: ../../build/doc/release_notes.rst:170 msgid "vrp_optimize" msgstr "" -#: ../../build/doc/release_notes.rst:170 +#: ../../build/doc/release_notes.rst:171 msgid "vrp_pickDeliverAdd" msgstr "" -#: ../../build/doc/release_notes.rst:171 +#: ../../build/doc/release_notes.rst:172 msgid "vrp_pickDeliver" msgstr "" -#: ../../build/doc/release_notes.rst:172 +#: ../../build/doc/release_notes.rst:173 msgid "vrp_simulation" msgstr "" -#: ../../build/doc/release_notes.rst:173 +#: ../../build/doc/release_notes.rst:174 msgid "vrp_viewRoute" msgstr "" -#: ../../build/doc/release_notes.rst:176 +#: ../../build/doc/release_notes.rst:177 msgid "vrpRouting 0.1" msgstr "" -#: ../../build/doc/release_notes.rst:179 +#: ../../build/doc/release_notes.rst:180 msgid "Extraction tasks" msgstr "" -#: ../../build/doc/release_notes.rst:180 +#: ../../build/doc/release_notes.rst:181 msgid "Porting pgRouting's VRP functionality" msgstr "" -#: ../../build/doc/release_notes.rst:183 +#: ../../build/doc/release_notes.rst:184 msgid "New official functions" msgstr "" diff --git a/sql/vroom/CMakeLists.txt b/sql/vroom/CMakeLists.txt index 9c629ae95..f9edecb9e 100644 --- a/sql/vroom/CMakeLists.txt +++ b/sql/vroom/CMakeLists.txt @@ -1,11 +1,11 @@ SET(LOCAL_FILES - _vrp_vroom.sql - vrp_vroom.sql - vrp_vroomJobs.sql - vrp_vroomShipments.sql - vrp_vroomPlain.sql - vrp_vroomJobsPlain.sql - vrp_vroomShipmentsPlain.sql + _vroom.sql + vroom.sql + vroomJobs.sql + vroomShipments.sql + vroomPlain.sql + vroomJobsPlain.sql + vroomShipmentsPlain.sql ) foreach (f ${LOCAL_FILES}) diff --git a/sql/vroom/_vrp_vroom.sql b/sql/vroom/_vroom.sql similarity index 100% rename from sql/vroom/_vrp_vroom.sql rename to sql/vroom/_vroom.sql diff --git a/sql/vroom/vrp_vroom.sql b/sql/vroom/vroom.sql similarity index 100% rename from sql/vroom/vrp_vroom.sql rename to sql/vroom/vroom.sql diff --git a/sql/vroom/vrp_vroomJobs.sql b/sql/vroom/vroomJobs.sql similarity index 100% rename from sql/vroom/vrp_vroomJobs.sql rename to sql/vroom/vroomJobs.sql diff --git a/sql/vroom/vrp_vroomJobsPlain.sql b/sql/vroom/vroomJobsPlain.sql similarity index 100% rename from sql/vroom/vrp_vroomJobsPlain.sql rename to sql/vroom/vroomJobsPlain.sql diff --git a/sql/vroom/vrp_vroomPlain.sql b/sql/vroom/vroomPlain.sql similarity index 100% rename from sql/vroom/vrp_vroomPlain.sql rename to sql/vroom/vroomPlain.sql diff --git a/sql/vroom/vrp_vroomShipments.sql b/sql/vroom/vroomShipments.sql similarity index 100% rename from sql/vroom/vrp_vroomShipments.sql rename to sql/vroom/vroomShipments.sql diff --git a/sql/vroom/vrp_vroomShipmentsPlain.sql b/sql/vroom/vroomShipmentsPlain.sql similarity index 100% rename from sql/vroom/vrp_vroomShipmentsPlain.sql rename to sql/vroom/vroomShipmentsPlain.sql diff --git a/src/common/e_report.c b/src/common/e_report.c index fe9266380..ba33dcce0 100644 --- a/src/common/e_report.c +++ b/src/common/e_report.c @@ -26,35 +26,61 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "c_common/postgres_connection.h" #include "c_common/e_report.h" +/** + * On C++ side, the message to be returned; + * ~~~~{.c} + * std::ostringstream log; + * log << "the message"; + * *log_msg = to_pg_msg(log.str().c_str()); + * ~~~~ + * + * Then on the C side + * ~~~~{.c} + * vrp_global_report(&log_msg, ¬ice_msg, &error_msg); + * ~~~~ + * + * - When there is ERROR then postgreSQL takes over control + * - The char* messages are cleared automaticalyy with pfree. + * - When there is no error this will free the log & notice + */ void -pgr_global_report( - char* log, - char* notice, - char* err) { - if (!notice && log) { +vrp_global_report( + char** log, + char** notice, + char** err) { + if (!(*notice) && (*log)) { ereport(DEBUG1, - (errmsg_internal("%s", log))); + (errmsg_internal("%s", *log))); } - if (notice) { + if (*notice) { if (log) { ereport(NOTICE, - (errmsg_internal("%s", notice), - errhint("%s", log))); + (errmsg_internal("%s", *notice), + errhint("%s", *log))); } else { ereport(NOTICE, - (errmsg_internal("%s", notice))); + (errmsg_internal("%s", *notice))); } } - if (err) { - if (log) { + if (*err) { + if (*log) { ereport(ERROR, - (errmsg_internal("%s", err), - errhint("%s", log))); + (errmsg_internal("%s", *err), + errhint("%s", *log))); } else { ereport(ERROR, - (errmsg_internal("%s", err))); + (errmsg_internal("%s", *err))); + } + } else { + if (*log) { + pfree(*log); + *log = NULL; + } + if (*notice) { + pfree(*notice); + *notice = NULL; } } } diff --git a/src/common/matrixRows_input.c b/src/common/matrixRows_input.c index f3a05b572..006cdd891 100644 --- a/src/common/matrixRows_input.c +++ b/src/common/matrixRows_input.c @@ -82,10 +82,10 @@ get_matrixRows_general( const int column_count = 3; void *SPIplan; - SPIplan = pgr_SPI_prepare(sql); + SPIplan = vrp_SPI_prepare(sql); Portal SPIportal; - SPIportal = pgr_SPI_cursor_open(SPIplan); + SPIportal = vrp_SPI_cursor_open(SPIplan); bool moredata = true; diff --git a/src/common/orders_input.c b/src/common/orders_input.c index d585e0f76..afdedbdad 100644 --- a/src/common/orders_input.c +++ b/src/common/orders_input.c @@ -42,7 +42,7 @@ void fetch_euclidean( HeapTuple *tuple, TupleDesc *tupdesc, Column_info_t *info, - PickDeliveryOrders_t *pd_order) { + Orders_t *pd_order) { pd_order->id = get_Id(tuple, tupdesc, info[0], -1); pd_order->demand = get_PositiveAmount(tuple, tupdesc, info[1], 0); @@ -78,7 +78,7 @@ void fetch_raw( HeapTuple *tuple, TupleDesc *tupdesc, Column_info_t *info, - PickDeliveryOrders_t *pd_order) { + Orders_t *pd_order) { pd_order->id = get_Id(tuple, tupdesc, info[0], -1); pd_order->demand = get_PositiveAmount(tuple, tupdesc, info[1], 0); @@ -113,7 +113,7 @@ void fetch_timestamps( HeapTuple *tuple, TupleDesc *tupdesc, Column_info_t *info, - PickDeliveryOrders_t *pd_order) { + Orders_t *pd_order) { pd_order->id = get_Id(tuple, tupdesc, info[0], -1); pd_order->demand = get_PositiveAmount(tuple, tupdesc, info[1], 0); @@ -150,7 +150,7 @@ static void pgr_get_pd_orders_general( char *pd_orders_sql, - PickDeliveryOrders_t **pd_orders, + Orders_t **pd_orders, size_t *total_pd_orders, Column_info_t *info, @@ -168,9 +168,9 @@ pgr_get_pd_orders_general( size_t total_tuples; void *SPIplan; - SPIplan = pgr_SPI_prepare(pd_orders_sql); + SPIplan = vrp_SPI_prepare(pd_orders_sql); Portal SPIportal; - SPIportal = pgr_SPI_cursor_open(SPIplan); + SPIportal = vrp_SPI_cursor_open(SPIplan); bool moredata = true; (*total_pd_orders) = total_tuples = 0; @@ -186,12 +186,12 @@ pgr_get_pd_orders_general( total_tuples += ntuples; if (ntuples > 0) { if ((*pd_orders) == NULL) - (*pd_orders) = (PickDeliveryOrders_t *)palloc0( - total_tuples * sizeof(PickDeliveryOrders_t)); + (*pd_orders) = (Orders_t *)palloc0( + total_tuples * sizeof(Orders_t)); else - (*pd_orders) = (PickDeliveryOrders_t *)repalloc( + (*pd_orders) = (Orders_t *)repalloc( (*pd_orders), - total_tuples * sizeof(PickDeliveryOrders_t)); + total_tuples * sizeof(Orders_t)); if ((*pd_orders) == NULL) { elog(ERROR, "Out of memory"); @@ -241,7 +241,7 @@ pgr_get_pd_orders_general( void get_shipments( char *sql, - PickDeliveryOrders_t **rows, + Orders_t **rows, size_t *total_rows) { const int column_count = 10; Column_info_t info[10]; @@ -286,7 +286,7 @@ get_shipments( void get_shipments_raw( char *sql, - PickDeliveryOrders_t **rows, + Orders_t **rows, size_t *total_rows) { const int column_count = 10; Column_info_t info[10]; @@ -324,7 +324,7 @@ get_shipments_raw( void get_shipments_euclidean( char *sql, - PickDeliveryOrders_t **rows, + Orders_t **rows, size_t *total_rows) { const int column_count = 12; Column_info_t info[12]; diff --git a/src/common/postgres_connection.c b/src/common/postgres_connection.c index ac24fa5c3..e2e3aa51a 100644 --- a/src/common/postgres_connection.c +++ b/src/common/postgres_connection.c @@ -32,43 +32,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "c_common/debug_macro.h" -void -pgr_send_error(int errcode) { - switch (errcode) { - case 1: - elog(ERROR, "Unexpected point(s) with same pid but different" - " edge/fraction/side combination found."); - break; - case 2: - elog(ERROR, "Internal: Unexpected mismatch " - "count and sequence number on results"); - break; - default: - elog(ERROR, "Unknown exception"); - } -} - - -char* -pgr_cstring2char(const char *inStr) { - if (!inStr) return NULL; - - char *outStr; - outStr = palloc(strlen(inStr)); - if (!outStr) return NULL; - - memcpy(outStr, inStr, strlen(inStr)); - - outStr[strlen(inStr)] = '\0'; - - return outStr; -} - // http://www.postgresql.org/docs/9.4/static/spi-spi-finish.html void -pgr_SPI_finish(void) { +vrp_SPI_finish(void) { int code = SPI_finish(); if (code != SPI_OK_FINISH) { // SPI_ERROR_UNCONNECTED elog(ERROR, "There was no connection to SPI"); @@ -76,7 +44,7 @@ pgr_SPI_finish(void) { } void -pgr_SPI_connect(void) { +vrp_SPI_connect(void) { int SPIcode; SPIcode = SPI_connect(); if (SPIcode != SPI_OK_CONNECT) { @@ -85,7 +53,7 @@ pgr_SPI_connect(void) { } SPIPlanPtr -pgr_SPI_prepare(char* sql) { +vrp_SPI_prepare(const char* sql) { SPIPlanPtr SPIplan; SPIplan = SPI_prepare(sql, 0, NULL); if (SPIplan == NULL) { @@ -95,7 +63,7 @@ pgr_SPI_prepare(char* sql) { } Portal -pgr_SPI_cursor_open(SPIPlanPtr SPIplan) { +vrp_SPI_cursor_open(SPIPlanPtr SPIplan) { Portal SPIportal; SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true); if (SPIportal == NULL) { diff --git a/src/common/time_multipliers_input.c b/src/common/time_multipliers_input.c index 05cbad2f0..4c31ef907 100644 --- a/src/common/time_multipliers_input.c +++ b/src/common/time_multipliers_input.c @@ -78,10 +78,10 @@ void get_timeMultipliersGeneral( const int column_count = 2; void *SPIplan; - SPIplan = pgr_SPI_prepare(sql); + SPIplan = vrp_SPI_prepare(sql); Portal SPIportal; - SPIportal = pgr_SPI_cursor_open(SPIplan); + SPIportal = vrp_SPI_cursor_open(SPIplan); bool moredata = true; diff --git a/src/common/vehicles_input.c b/src/common/vehicles_input.c index af7ae879c..8ae5dd2be 100644 --- a/src/common/vehicles_input.c +++ b/src/common/vehicles_input.c @@ -245,9 +245,9 @@ void db_get_vehicles( size_t total_tuples; void *SPIplan; - SPIplan = pgr_SPI_prepare(vehicles_sql); + SPIplan = vrp_SPI_prepare(vehicles_sql); Portal SPIportal; - SPIportal = pgr_SPI_cursor_open(SPIplan); + SPIportal = vrp_SPI_cursor_open(SPIplan); bool moredata = true; (*total_vehicles) = total_tuples = 0; diff --git a/src/common/vroom/breaks_input.c b/src/common/vroom/breaks_input.c index e4042d87e..c454fb311 100644 --- a/src/common/vroom/breaks_input.c +++ b/src/common/vroom/breaks_input.c @@ -68,9 +68,9 @@ void db_get_breaks( size_t total_tuples; void *SPIplan; - SPIplan = pgr_SPI_prepare(breaks_sql); + SPIplan = vrp_SPI_prepare(breaks_sql); Portal SPIportal; - SPIportal = pgr_SPI_cursor_open(SPIplan); + SPIportal = vrp_SPI_cursor_open(SPIplan); bool moredata = true; (*total_breaks) = total_tuples = 0; diff --git a/src/common/vroom/jobs_input.c b/src/common/vroom/jobs_input.c index 0ff3b5186..606be98bb 100644 --- a/src/common/vroom/jobs_input.c +++ b/src/common/vroom/jobs_input.c @@ -94,9 +94,9 @@ void db_get_jobs( size_t total_tuples; void *SPIplan; - SPIplan = pgr_SPI_prepare(jobs_sql); + SPIplan = vrp_SPI_prepare(jobs_sql); Portal SPIportal; - SPIportal = pgr_SPI_cursor_open(SPIplan); + SPIportal = vrp_SPI_cursor_open(SPIplan); bool moredata = true; (*total_jobs) = total_tuples = 0; diff --git a/src/common/vroom/matrix_input.c b/src/common/vroom/matrix_input.c index fafbead30..9b4d15692 100644 --- a/src/common/vroom/matrix_input.c +++ b/src/common/vroom/matrix_input.c @@ -67,9 +67,9 @@ void db_get_matrix( size_t total_tuples; void *SPIplan; - SPIplan = pgr_SPI_prepare(matrix_sql); + SPIplan = vrp_SPI_prepare(matrix_sql); Portal SPIportal; - SPIportal = pgr_SPI_cursor_open(SPIplan); + SPIportal = vrp_SPI_cursor_open(SPIplan); bool moredata = true; (*total_matrix_rows) = total_tuples = 0; diff --git a/src/common/vroom/shipments_input.c b/src/common/vroom/shipments_input.c index 9d3df4a88..1ce42b5f0 100644 --- a/src/common/vroom/shipments_input.c +++ b/src/common/vroom/shipments_input.c @@ -96,9 +96,9 @@ void db_get_shipments( size_t total_tuples; void *SPIplan; - SPIplan = pgr_SPI_prepare(shipments_sql); + SPIplan = vrp_SPI_prepare(shipments_sql); Portal SPIportal; - SPIportal = pgr_SPI_cursor_open(SPIplan); + SPIportal = vrp_SPI_cursor_open(SPIplan); bool moredata = true; (*total_shipments) = total_tuples = 0; diff --git a/src/common/vroom/time_windows_input.c b/src/common/vroom/time_windows_input.c index b753b42c0..c7c212260 100644 --- a/src/common/vroom/time_windows_input.c +++ b/src/common/vroom/time_windows_input.c @@ -98,9 +98,9 @@ void db_get_time_windows( size_t total_tuples; void *SPIplan; - SPIplan = pgr_SPI_prepare(time_windows_sql); + SPIplan = vrp_SPI_prepare(time_windows_sql); Portal SPIportal; - SPIportal = pgr_SPI_cursor_open(SPIplan); + SPIportal = vrp_SPI_cursor_open(SPIplan); bool moredata = true; (*total_time_windows) = total_tuples = 0; diff --git a/src/common/vroom/vehicles_input.c b/src/common/vroom/vehicles_input.c index 05b80d500..4b4f716d1 100644 --- a/src/common/vroom/vehicles_input.c +++ b/src/common/vroom/vehicles_input.c @@ -106,9 +106,9 @@ void db_get_vehicles( size_t total_tuples; void *SPIplan; - SPIplan = pgr_SPI_prepare(vehicles_sql); + SPIplan = vrp_SPI_prepare(vehicles_sql); Portal SPIportal; - SPIportal = pgr_SPI_cursor_open(SPIplan); + SPIportal = vrp_SPI_cursor_open(SPIplan); bool moredata = true; (*total_vehicles) = total_tuples = 0; diff --git a/src/compatibleVehicles/compatibleVehicles.c b/src/compatibleVehicles/compatibleVehicles.c index 79d23a8e4..319b5f064 100644 --- a/src/compatibleVehicles/compatibleVehicles.c +++ b/src/compatibleVehicles/compatibleVehicles.c @@ -62,9 +62,9 @@ process( errhint("Value found: %f <= 0", factor))); } - pgr_SPI_connect(); + vrp_SPI_connect(); - PickDeliveryOrders_t *pd_orders_arr = NULL; + Orders_t *pd_orders_arr = NULL; size_t total_pd_orders = 0; if (use_timestamps) { @@ -82,7 +82,7 @@ process( pfree(pd_orders_arr); pd_orders_arr = NULL; } - pgr_SPI_finish(); + vrp_SPI_finish(); return; } @@ -106,7 +106,7 @@ process( pfree(vehicles_arr); vehicles_arr = NULL; } - pgr_SPI_finish(); + vrp_SPI_finish(); return; } @@ -133,7 +133,7 @@ process( pfree(multipliers_arr); multipliers_arr = NULL; } - pgr_SPI_finish(); + vrp_SPI_finish(); return; } @@ -163,7 +163,7 @@ process( pfree(matrix_cells_arr); matrix_cells_arr = NULL; } - pgr_SPI_finish(); + vrp_SPI_finish(); return; } @@ -203,18 +203,9 @@ process( (*result_tuples) = NULL; } - pgr_global_report(log_msg, notice_msg, err_msg); + vrp_global_report(&log_msg, ¬ice_msg, &err_msg); /* freeing memory before return */ - if (log_msg) { - pfree(log_msg); log_msg = NULL; - } - if (notice_msg) { - pfree(notice_msg); notice_msg = NULL; - } - if (err_msg) { - pfree(err_msg); err_msg = NULL; - } if (pd_orders_arr) { pfree(pd_orders_arr); pd_orders_arr = NULL; } @@ -228,36 +219,24 @@ process( pfree(matrix_cells_arr); matrix_cells_arr = NULL; } - pgr_SPI_finish(); + vrp_SPI_finish(); } -/******************************************************************************/ - - PGDLLEXPORT Datum _vrp_compatiblevehicles(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; TupleDesc tuple_desc; - /**************************************************************************/ CompatibleVehicles_rt *result_tuples = 0; size_t result_count = 0; - /**************************************************************************/ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - /********************************************************************** - orders_sql TEXT, - vehicles_sql TEXT, - matrix_cell_sql TEXT, - factor FLOAT DEFAULT 1, - **********************************************************************/ - process( text_to_cstring(PG_GETARG_TEXT_P(0)), text_to_cstring(PG_GETARG_TEXT_P(1)), @@ -268,8 +247,6 @@ _vrp_compatiblevehicles(PG_FUNCTION_ARGS) { &result_tuples, &result_count); - /*********************************************************************/ - funcctx->max_calls = result_count; funcctx->user_fctx = result_tuples; if (get_call_result_type(fcinfo, NULL, &tuple_desc) diff --git a/src/compatibleVehicles/compatibleVehicles_driver.cpp b/src/compatibleVehicles/compatibleVehicles_driver.cpp index c9f776eaa..5f41c67ca 100644 --- a/src/compatibleVehicles/compatibleVehicles_driver.cpp +++ b/src/compatibleVehicles/compatibleVehicles_driver.cpp @@ -96,7 +96,7 @@ digraph G { */ void do_compatibleVehicles( - PickDeliveryOrders_t customers_arr[], + Orders_t customers_arr[], size_t total_customers, Vehicle_t *vehicles_arr, @@ -116,6 +116,9 @@ do_compatibleVehicles( char **log_msg, char **notice_msg, char **err_msg) { + using vrprouting::alloc; + using vrprouting::to_pg_msg; + std::ostringstream log; std::ostringstream notice; std::ostringstream err; @@ -150,9 +153,9 @@ do_compatibleVehicles( * Verify matrix cells preconditions */ vrprouting::problem::Matrix cost_matrix( - matrix_cells_arr, total_cells, - multipliers_arr, total_multipliers, - node_ids, static_cast(factor)); + matrix_cells_arr, total_cells, + multipliers_arr, total_multipliers, + node_ids, static_cast(factor)); #if 0 /* * Verify matrix triangle inequality @@ -168,7 +171,7 @@ do_compatibleVehicles( #endif if (!cost_matrix.has_no_infinity()) { err << "An Infinity value was found on the Matrix"; - *err_msg = pgr_msg(err.str()); + *err_msg = to_pg_msg(err.str()); return; } @@ -184,8 +187,8 @@ do_compatibleVehicles( err << pd_problem.msg.get_error(); if (!err.str().empty()) { log << pd_problem.msg.get_log(); - *log_msg = pgr_msg(log.str()); - *err_msg = pgr_msg(err.str()); + *log_msg = to_pg_msg(log.str()); + *err_msg = to_pg_msg(err.str()); return; } log << pd_problem.msg.get_log(); @@ -201,7 +204,7 @@ do_compatibleVehicles( if (!solution.empty()) { log << "solution empty " << "\n"; - (*return_tuples) = pgr_alloc(solution.size(), (*return_tuples)); + (*return_tuples) = alloc(solution.size(), (*return_tuples)); int seq = 0; for (const auto &row : solution) { (*return_tuples)[seq] = row; @@ -214,27 +217,27 @@ do_compatibleVehicles( pgassert(*err_msg == nullptr); *log_msg = log.str().empty()? nullptr : - pgr_msg(log.str()); + to_pg_msg(log.str()); *notice_msg = notice.str().empty()? nullptr : - pgr_msg(notice.str()); + to_pg_msg(notice.str()); } catch (AssertFailedException &except) { if (*return_tuples) free(*return_tuples); (*return_count) = 0; err << except.what(); - *err_msg = pgr_msg(err.str()); - *log_msg = pgr_msg(log.str()); + *err_msg = to_pg_msg(err.str()); + *log_msg = to_pg_msg(log.str()); } catch (std::exception& except) { if (*return_tuples) free(*return_tuples); (*return_count) = 0; err << except.what(); - *err_msg = pgr_msg(err.str()); - *log_msg = pgr_msg(log.str()); + *err_msg = to_pg_msg(err.str()); + *log_msg = to_pg_msg(log.str()); } catch(...) { if (*return_tuples) free(*return_tuples); (*return_count) = 0; err << "Caught unknown exception!"; - *err_msg = pgr_msg(err.str()); - *log_msg = pgr_msg(log.str()); + *err_msg = to_pg_msg(err.str()); + *log_msg = to_pg_msg(log.str()); } } diff --git a/src/cpp_common/alloc.cpp b/src/cpp_common/alloc.cpp index 81d121c0b..25936819e 100644 --- a/src/cpp_common/alloc.cpp +++ b/src/cpp_common/alloc.cpp @@ -29,12 +29,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include #include -char * -pgr_msg(const std::string &msg) { +namespace vrprouting { + +char* to_pg_msg(const std::string &msg) { char* duplicate = nullptr; - duplicate = pgr_alloc(msg.size() + 1, duplicate); + duplicate = alloc(msg.size() + 1, duplicate); memcpy(duplicate, msg.c_str(), msg.size()); duplicate[msg.size()] = '\0'; return duplicate; } +} // namespace vrprouting diff --git a/src/cpp_common/messages.cpp b/src/cpp_common/messages.cpp index 8a8d35384..439db6971 100644 --- a/src/cpp_common/messages.cpp +++ b/src/cpp_common/messages.cpp @@ -33,30 +33,30 @@ namespace vrprouting { std::string -Pgr_messages::get_log() const { +Messages::get_log() const { auto str = log.str(); return str; } std::string -Pgr_messages::get_notice() const { +Messages::get_notice() const { auto str = notice.str(); return str; } bool -Pgr_messages::has_error() const { +Messages::has_error() const { return !error.str().empty(); } std::string -Pgr_messages::get_error() const { +Messages::get_error() const { auto str = error.str(); return str; } void -Pgr_messages::clear() { +Messages::clear() { log.str(""); log.clear(); diff --git a/src/optimize/optimize.c b/src/optimize/optimize.c index a5b1abcea..071019b4e 100644 --- a/src/optimize/optimize.c +++ b/src/optimize/optimize.c @@ -47,239 +47,224 @@ PG_FUNCTION_INFO_V1(_vrp_optimize); static void process( - char* pd_orders_sql, - char* vehicles_sql, - char* matrix_sql, - char* multipliers_sql, - - double factor, - int max_cycles, - int64_t execution_date, - - bool check_triangle_inequality, - int subdivision_kind, - bool use_timestamps, - - Short_vehicle_rt **result_tuples, - size_t *result_count) { - //! [Factor must be postive] - if (factor <= 0) { - ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Illegal value in parameter: factor"), - errhint("Value found: %f <= 0", factor))); - } - - //! [max_cycles must be postive] - if (max_cycles < 0) { - ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Illegal value in parameter: max_cycles"), - errhint("Value found: %d <= 0", max_cycles))); - } - - //! [subdivision_kind can be: 0, 1, or 2] - if (subdivision_kind < 0 || subdivision_kind > 2) { - ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Illegal value in parameter: subdivision_kind"), - errhint("Value found: %d", max_cycles))); - } + char* pd_orders_sql, + char* vehicles_sql, + char* matrix_sql, + char* multipliers_sql, + + double factor, + int max_cycles, + int64_t execution_date, + + bool check_triangle_inequality, + int subdivision_kind, + bool use_timestamps, + + Short_vehicle_rt **result_tuples, + size_t *result_count) { + //! [Factor must be postive] + if (factor <= 0) { + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Illegal value in parameter: factor"), + errhint("Value found: %f <= 0", factor))); + } - pgr_SPI_connect(); + //! [max_cycles must be postive] + if (max_cycles < 0) { + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Illegal value in parameter: max_cycles"), + errhint("Value found: %d <= 0", max_cycles))); + } - PickDeliveryOrders_t *pd_orders_arr = NULL; - size_t total_pd_orders = 0; - if (use_timestamps) { - get_shipments(pd_orders_sql, &pd_orders_arr, &total_pd_orders); - } else { - get_shipments_raw(pd_orders_sql, &pd_orders_arr, &total_pd_orders); - } + //! [subdivision_kind can be: 0, 1, or 2] + if (subdivision_kind < 0 || subdivision_kind > 2) { + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Illegal value in parameter: subdivision_kind"), + errhint("Value found: %d", max_cycles))); + } - if (total_pd_orders == 0) { - (*result_count) = 0; - (*result_tuples) = NULL; + vrp_SPI_connect(); - /* freeing memory before return */ - if (pd_orders_arr) { - pfree(pd_orders_arr); pd_orders_arr = NULL; + Orders_t *pd_orders_arr = NULL; + size_t total_pd_orders = 0; + if (use_timestamps) { + get_shipments(pd_orders_sql, &pd_orders_arr, &total_pd_orders); + } else { + get_shipments_raw(pd_orders_sql, &pd_orders_arr, &total_pd_orders); } - pgr_SPI_finish(); - return; - } - - Vehicle_t *vehicles_arr = NULL; - size_t total_vehicles = 0; - if (use_timestamps) { - get_vehicles(vehicles_sql, &vehicles_arr, &total_vehicles, true); - } else { - get_vehicles_raw(vehicles_sql, &vehicles_arr, &total_vehicles, true); - } + if (total_pd_orders == 0) { + (*result_count) = 0; + (*result_tuples) = NULL; - if (total_vehicles == 0) { - (*result_count) = 0; - (*result_tuples) = NULL; + /* freeing memory before return */ + if (pd_orders_arr) { + pfree(pd_orders_arr); pd_orders_arr = NULL; + } - /* freeing memory before return */ - if (pd_orders_arr) { - pfree(pd_orders_arr); pd_orders_arr = NULL; + vrp_SPI_finish(); + return; } - if (vehicles_arr) { - pfree(vehicles_arr); vehicles_arr = NULL; + + Vehicle_t *vehicles_arr = NULL; + size_t total_vehicles = 0; + if (use_timestamps) { + get_vehicles(vehicles_sql, &vehicles_arr, &total_vehicles, true); + } else { + get_vehicles_raw(vehicles_sql, &vehicles_arr, &total_vehicles, true); } - ereport(WARNING, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("No vehicles found"))); + if (total_vehicles == 0) { + (*result_count) = 0; + (*result_tuples) = NULL; - pgr_SPI_finish(); - return; - } + /* freeing memory before return */ + if (pd_orders_arr) { + pfree(pd_orders_arr); pd_orders_arr = NULL; + } + if (vehicles_arr) { + pfree(vehicles_arr); vehicles_arr = NULL; + } - Time_multipliers_t *multipliers_arr = NULL; - size_t total_multipliers_arr = 0; - if (use_timestamps) { - get_timeMultipliers(multipliers_sql, &multipliers_arr, &total_multipliers_arr); - } else { - get_timeMultipliers_raw(multipliers_sql, &multipliers_arr, &total_multipliers_arr); - } + ereport(WARNING, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("No vehicles found"))); - if (total_multipliers_arr == 0) { - ereport(WARNING, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("No matrix found"))); - (*result_count) = 0; - (*result_tuples) = NULL; + vrp_SPI_finish(); + return; + } - /* freeing memory before return */ - if (pd_orders_arr) { - pfree(pd_orders_arr); pd_orders_arr = NULL; + Time_multipliers_t *multipliers_arr = NULL; + size_t total_multipliers_arr = 0; + if (use_timestamps) { + get_timeMultipliers(multipliers_sql, &multipliers_arr, &total_multipliers_arr); + } else { + get_timeMultipliers_raw(multipliers_sql, &multipliers_arr, &total_multipliers_arr); } - if (vehicles_arr) { - pfree(vehicles_arr); vehicles_arr = NULL; + + if (total_multipliers_arr == 0) { + ereport(WARNING, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("No matrix found"))); + (*result_count) = 0; + (*result_tuples) = NULL; + + /* freeing memory before return */ + if (pd_orders_arr) { + pfree(pd_orders_arr); pd_orders_arr = NULL; + } + if (vehicles_arr) { + pfree(vehicles_arr); vehicles_arr = NULL; + } + if (multipliers_arr) { + pfree(multipliers_arr); multipliers_arr = NULL; + } + + vrp_SPI_finish(); + return; } - if (multipliers_arr) { - pfree(multipliers_arr); multipliers_arr = NULL; + + Matrix_cell_t *matrix_cells_arr = NULL; + size_t total_cells = 0; + if (use_timestamps) { + get_matrixRows(matrix_sql, &matrix_cells_arr, &total_cells); + } else { + get_matrixRows_plain(matrix_sql, &matrix_cells_arr, &total_cells); } - pgr_SPI_finish(); - return; - } + if (total_cells == 0) { + (*result_count) = 0; + (*result_tuples) = NULL; + + /* freeing memory before return */ + if (pd_orders_arr) { + pfree(pd_orders_arr); pd_orders_arr = NULL; + } + if (vehicles_arr) { + pfree(vehicles_arr); vehicles_arr = NULL; + } + if (multipliers_arr) { + pfree(multipliers_arr); multipliers_arr = NULL; + } + if (matrix_cells_arr) { + pfree(matrix_cells_arr); matrix_cells_arr = NULL; + } + + ereport(WARNING, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("No matrix found"))); + vrp_SPI_finish(); + return; + } - Matrix_cell_t *matrix_cells_arr = NULL; - size_t total_cells = 0; - if (use_timestamps) { - get_matrixRows(matrix_sql, &matrix_cells_arr, &total_cells); - } else { - get_matrixRows_plain(matrix_sql, &matrix_cells_arr, &total_cells); - } + PGR_DBG("Total %ld orders in query:", total_pd_orders); + PGR_DBG("Total %ld vehicles in query:", total_vehicles); + PGR_DBG("Total %ld matrix cells in query:", total_cells); + PGR_DBG("Total %ld time dependant multipliers:", total_multipliers_arr); - if (total_cells == 0) { - (*result_count) = 0; - (*result_tuples) = NULL; + clock_t start_t = clock(); + char *log_msg = NULL; + char *notice_msg = NULL; + char *err_msg = NULL; + + do_optimize( + pd_orders_arr, total_pd_orders, + vehicles_arr, total_vehicles, + matrix_cells_arr, total_cells, + multipliers_arr, total_multipliers_arr, + + factor, + max_cycles, + execution_date, + + check_triangle_inequality, + subdivision_kind != 0, + subdivision_kind == 1, + + result_tuples, + result_count, + + &log_msg, + ¬ice_msg, + &err_msg); + + time_msg("pgr_pickDeliver", start_t, clock()); + + if (err_msg && (*result_tuples)) { + pfree(*result_tuples); + (*result_count) = 0; + (*result_tuples) = NULL; + } + vrp_global_report(&log_msg, ¬ice_msg, &err_msg); /* freeing memory before return */ if (pd_orders_arr) { - pfree(pd_orders_arr); pd_orders_arr = NULL; + pfree(pd_orders_arr); pd_orders_arr = NULL; } if (vehicles_arr) { - pfree(vehicles_arr); vehicles_arr = NULL; + pfree(vehicles_arr); vehicles_arr = NULL; } if (multipliers_arr) { - pfree(multipliers_arr); multipliers_arr = NULL; + pfree(multipliers_arr); multipliers_arr = NULL; } if (matrix_cells_arr) { - pfree(matrix_cells_arr); matrix_cells_arr = NULL; + pfree(matrix_cells_arr); matrix_cells_arr = NULL; } - ereport(WARNING, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("No matrix found"))); - pgr_SPI_finish(); - return; - } - - PGR_DBG("Total %ld orders in query:", total_pd_orders); - PGR_DBG("Total %ld vehicles in query:", total_vehicles); - PGR_DBG("Total %ld matrix cells in query:", total_cells); - PGR_DBG("Total %ld time dependant multipliers:", total_multipliers_arr); - - clock_t start_t = clock(); - char *log_msg = NULL; - char *notice_msg = NULL; - char *err_msg = NULL; - - do_optimize( - pd_orders_arr, total_pd_orders, - vehicles_arr, total_vehicles, - matrix_cells_arr, total_cells, - multipliers_arr, total_multipliers_arr, - - factor, - max_cycles, - execution_date, - - check_triangle_inequality, - subdivision_kind != 0, - subdivision_kind == 1, - - result_tuples, - result_count, - - &log_msg, - ¬ice_msg, - &err_msg); - - time_msg("pgr_pickDeliver", start_t, clock()); - - if (err_msg && (*result_tuples)) { - pfree(*result_tuples); - (*result_count) = 0; - (*result_tuples) = NULL; - } - pgr_global_report(log_msg, notice_msg, err_msg); - - /* freeing memory before return */ - if (log_msg) { - pfree(log_msg); log_msg = NULL; - } - if (notice_msg) { - pfree(notice_msg); notice_msg = NULL; - } - if (err_msg) { - pfree(err_msg); err_msg = NULL; - } - if (pd_orders_arr) { - pfree(pd_orders_arr); pd_orders_arr = NULL; - } - if (vehicles_arr) { - pfree(vehicles_arr); vehicles_arr = NULL; - } - if (multipliers_arr) { - pfree(multipliers_arr); multipliers_arr = NULL; - } - if (matrix_cells_arr) { - pfree(matrix_cells_arr); matrix_cells_arr = NULL; - } - - pgr_SPI_finish(); + vrp_SPI_finish(); } - -/******************************************************************************/ - - PGDLLEXPORT Datum _vrp_optimize(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; TupleDesc tuple_desc; - /**************************************************************************/ Short_vehicle_rt *result_tuples = 0; size_t result_count = 0; - /**************************************************************************/ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; @@ -303,13 +288,7 @@ _vrp_optimize(PG_FUNCTION_ARGS) { &result_tuples, &result_count); - /*********************************************************************/ - -#if PGSQL_VERSION > 95 funcctx->max_calls = result_count; -#else - funcctx->max_calls = (uint32_t)result_count; -#endif funcctx->user_fctx = result_tuples; if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE) { @@ -348,8 +327,6 @@ _vrp_optimize(PG_FUNCTION_ARGS) { values[1] = Int64GetDatum(result_tuples[call_cntr].vehicle_id); values[2] = Int64GetDatum(result_tuples[call_cntr].order_id); - /*********************************************************************/ - tuple = heap_form_tuple(tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); diff --git a/src/optimize/optimize_driver.cpp b/src/optimize/optimize_driver.cpp index 1d11b3f29..d3b17faed 100644 --- a/src/optimize/optimize_driver.cpp +++ b/src/optimize/optimize_driver.cpp @@ -67,48 +67,48 @@ namespace { */ std::vector one_processing( - PickDeliveryOrders_t *shipments_arr, size_t total_shipments, - Vehicle_t *vehicles_arr, size_t total_vehicles, - std::vector new_stops, - const vrprouting::problem::Matrix &time_matrix, - int max_cycles, - int64_t execution_date) { - try { - /* - * Construct problem - */ - vrprouting::problem::PickDeliver pd_problem( - shipments_arr, total_shipments, - vehicles_arr, total_vehicles, - new_stops, - time_matrix); - - /* - * Unknown problem when createing the pick Deliver problem - */ - if (!pd_problem.msg.get_error().empty()) { - throw std::make_pair(pd_problem.msg.get_error(), pd_problem.msg.get_log()); - } + Orders_t *shipments_arr, size_t total_shipments, + Vehicle_t *vehicles_arr, size_t total_vehicles, + std::vector new_stops, + const vrprouting::problem::Matrix &time_matrix, + int max_cycles, + int64_t execution_date) { + try { + /* + * Construct problem + */ + vrprouting::problem::PickDeliver pd_problem( + shipments_arr, total_shipments, + vehicles_arr, total_vehicles, + new_stops, + time_matrix); + + /* + * Unknown problem when createing the pick Deliver problem + */ + if (!pd_problem.msg.get_error().empty()) { + throw std::make_pair(pd_problem.msg.get_error(), pd_problem.msg.get_log()); + } - /* - * get initial solution - */ - using Initial_solution = vrprouting::initialsol::tabu::Initial_solution; - using Solution = vrprouting::problem::Solution; - auto sol = static_cast(Initial_solution(execution_date, true, &pd_problem)); - - /* - * Optimize the initial solution: - * - false: do not stop on all served - * - true: optimize - */ - using Optimize = vrprouting::optimizers::tabu::Optimize; - sol = Optimize(sol, static_cast(max_cycles), false, true); - - return sol.get_stops(); - } catch(...) { - throw; - } + /* + * get initial solution + */ + using Initial_solution = vrprouting::initialsol::tabu::Initial_solution; + using Solution = vrprouting::problem::Solution; + auto sol = static_cast(Initial_solution(execution_date, true, &pd_problem)); + + /* + * Optimize the initial solution: + * - false: do not stop on all served + * - true: optimize + */ + using Optimize = vrprouting::optimizers::tabu::Optimize; + sol = Optimize(sol, static_cast(max_cycles), false, true); + + return sol.get_stops(); + } catch(...) { + throw; + } } @@ -121,16 +121,16 @@ one_processing( */ Identifiers processing_times_by_shipment( - PickDeliveryOrders_t *shipments_arr, size_t total_shipments - ) { - Identifiers processing_times; - for (size_t i = 0; i < total_shipments; ++i) { - processing_times += shipments_arr[i].pick_open_t; - processing_times += shipments_arr[i].pick_close_t; - processing_times += shipments_arr[i].deliver_open_t; - processing_times += shipments_arr[i].deliver_close_t; - } - return processing_times; + Orders_t *shipments_arr, size_t total_shipments + ) { + Identifiers processing_times; + for (size_t i = 0; i < total_shipments; ++i) { + processing_times += shipments_arr[i].pick_open_t; + processing_times += shipments_arr[i].pick_close_t; + processing_times += shipments_arr[i].deliver_open_t; + processing_times += shipments_arr[i].deliver_close_t; + } + return processing_times; } /** @brief: extract the times where the vehicle opens or closes @@ -142,16 +142,16 @@ processing_times_by_shipment( */ Identifiers processing_times_by_vehicle( - Vehicle_t *vehicles_arr, size_t total_vehicles - ) { - Identifiers processing_times; - for (size_t i = 0; i < total_vehicles; ++i) { - processing_times += vehicles_arr[i].start_open_t; - processing_times += vehicles_arr[i].start_close_t; - processing_times += vehicles_arr[i].end_open_t; - processing_times += vehicles_arr[i].end_close_t; - } - return processing_times; + Vehicle_t *vehicles_arr, size_t total_vehicles + ) { + Identifiers processing_times; + for (size_t i = 0; i < total_vehicles; ++i) { + processing_times += vehicles_arr[i].start_open_t; + processing_times += vehicles_arr[i].start_close_t; + processing_times += vehicles_arr[i].end_open_t; + processing_times += vehicles_arr[i].end_close_t; + } + return processing_times; } /** @brief get the original stops @@ -163,19 +163,19 @@ processing_times_by_vehicle( */ std::vector get_initial_stops( - Vehicle_t *vehicles_arr, size_t total_vehicles - ) { - std::vector the_stops; - for (size_t i = 0; i < total_vehicles; ++i) { - std::vector stops; - for (size_t j = 0; j < vehicles_arr[i].stops_size; ++j) { - stops.push_back(vehicles_arr[i].stops[j]); + Vehicle_t *vehicles_arr, size_t total_vehicles + ) { + std::vector the_stops; + for (size_t i = 0; i < total_vehicles; ++i) { + std::vector stops; + for (size_t j = 0; j < vehicles_arr[i].stops_size; ++j) { + stops.push_back(vehicles_arr[i].stops[j]); + } + the_stops.push_back({vehicles_arr[i].id, stops}); } - the_stops.push_back({vehicles_arr[i].id, stops}); - } - std::sort(the_stops.begin(), the_stops.end(), [] - (const Short_vehicle &lhs, const Short_vehicle &rhs) {return lhs.id < rhs.id;}); - return the_stops; + std::sort(the_stops.begin(), the_stops.end(), [] + (const Short_vehicle &lhs, const Short_vehicle &rhs) {return lhs.id < rhs.id;}); + return the_stops; } /** @brief Update the vehicle stops to the new values @@ -185,15 +185,15 @@ get_initial_stops( */ void update_stops(std::vector& the_stops, // NOLINT [runtime/references] - const std::vector new_values) { - for (const auto &v : new_values) { - auto v_id = v.id; - auto v_to_modify = std::find_if( - the_stops.begin(), the_stops.end(), [v_id] - (const Short_vehicle& v) -> bool {return v.id == v_id;}); - pgassert(v_to_modify != the_stops.end()); - v_to_modify->stops = v.stops; - } + const std::vector new_values) { + for (const auto &v : new_values) { + auto v_id = v.id; + auto v_to_modify = std::find_if( + the_stops.begin(), the_stops.end(), [v_id] + (const Short_vehicle& v) -> bool {return v.id == v_id;}); + pgassert(v_to_modify != the_stops.end()); + v_to_modify->stops = v.stops; + } } /** @brief Executes an optimization by subdivision of data @@ -211,76 +211,76 @@ update_stops(std::vector& the_stops, // NOLINT [runtime/referenc */ std::vector subdivide_processing( - PickDeliveryOrders_t *shipments_arr, size_t total_shipments, - Vehicle_t *vehicles_arr, size_t total_vehicles, - const vrprouting::problem::Matrix &time_matrix, - int max_cycles, - int64_t execution_date, - bool subdivide_by_vehicle, - std::ostringstream &log) { - try { - auto the_stops = get_initial_stops(vehicles_arr, total_vehicles); - - auto processing_times = subdivide_by_vehicle? - processing_times_by_vehicle(vehicles_arr, total_vehicles) - : processing_times_by_shipment(shipments_arr, total_shipments); - - Identifiers prev_shipments_in_stops; - for (const auto &t : processing_times) { - CHECK_FOR_INTERRUPTS(); - /* - * Get active vehicles at time t - */ - auto vehicles_to_process = static_cast(std::distance(vehicles_arr, - std::partition( - vehicles_arr, vehicles_arr + total_vehicles, - [&](const Vehicle_t& v) - {return v.start_open_t <= t && t <= v.end_close_t;}))); - - /* Get shipments in stops of active vehicles */ - Identifiers shipments_in_stops; - for (size_t i = 0; i < vehicles_to_process; ++i) { - auto v_id = vehicles_arr[i].id; - auto v_to_modify = std::find_if( - the_stops.begin(), the_stops.end(), [&] - (const Short_vehicle& v) -> bool {return v.id == v_id;}); - - for (const auto &s : v_to_modify->stops) { - shipments_in_stops += s; + Orders_t *shipments_arr, size_t total_shipments, + Vehicle_t *vehicles_arr, size_t total_vehicles, + const vrprouting::problem::Matrix &time_matrix, + int max_cycles, + int64_t execution_date, + bool subdivide_by_vehicle, + std::ostringstream &log) { + try { + auto the_stops = get_initial_stops(vehicles_arr, total_vehicles); + + auto processing_times = subdivide_by_vehicle? + processing_times_by_vehicle(vehicles_arr, total_vehicles) + : processing_times_by_shipment(shipments_arr, total_shipments); + + Identifiers prev_shipments_in_stops; + for (const auto &t : processing_times) { + CHECK_FOR_INTERRUPTS(); + /* + * Get active vehicles at time t + */ + auto vehicles_to_process = static_cast(std::distance(vehicles_arr, + std::partition( + vehicles_arr, vehicles_arr + total_vehicles, + [&](const Vehicle_t& v) + {return v.start_open_t <= t && t <= v.end_close_t;}))); + + /* Get shipments in stops of active vehicles */ + Identifiers shipments_in_stops; + for (size_t i = 0; i < vehicles_to_process; ++i) { + auto v_id = vehicles_arr[i].id; + auto v_to_modify = std::find_if( + the_stops.begin(), the_stops.end(), [&] + (const Short_vehicle& v) -> bool {return v.id == v_id;}); + + for (const auto &s : v_to_modify->stops) { + shipments_in_stops += s; + } + } + + /* + * Nothing to do: + * - no shipments to process + * - last optimization had exavtly the same shipments + */ + if ((shipments_in_stops.size() == 0) + || (prev_shipments_in_stops == shipments_in_stops)) continue; + log << "\nOptimizing at time: " << t; + + prev_shipments_in_stops = shipments_in_stops; + + auto shipments_to_process = static_cast(std::distance(shipments_arr, + std::partition(shipments_arr, shipments_arr + total_shipments, + [&](const Orders_t& s){return shipments_in_stops.has(s.id);}))); + + pgassert(shipments_to_process > 0); + pgassert(shipments_in_stops.size() == static_cast(shipments_to_process)); + + auto new_stops = one_processing( + shipments_arr, shipments_to_process, + vehicles_arr, vehicles_to_process, the_stops, + time_matrix, + max_cycles, execution_date); + + update_stops(the_stops, new_stops); } - } - - /* - * Nothing to do: - * - no shipments to process - * - last optimization had exavtly the same shipments - */ - if ((shipments_in_stops.size() == 0) - || (prev_shipments_in_stops == shipments_in_stops)) continue; - log << "\nOptimizing at time: " << t; - - prev_shipments_in_stops = shipments_in_stops; - - auto shipments_to_process = static_cast(std::distance(shipments_arr, - std::partition(shipments_arr, shipments_arr + total_shipments, - [&](const PickDeliveryOrders_t& s){return shipments_in_stops.has(s.id);}))); - - pgassert(shipments_to_process > 0); - pgassert(shipments_in_stops.size() == static_cast(shipments_to_process)); - auto new_stops = one_processing( - shipments_arr, shipments_to_process, - vehicles_arr, vehicles_to_process, the_stops, - time_matrix, - max_cycles, execution_date); - - update_stops(the_stops, new_stops); + return the_stops; + } catch(...) { + throw; } - - return the_stops; - } catch(...) { - throw; - } } @@ -348,199 +348,202 @@ subdivide_processing( void do_optimize( - PickDeliveryOrders_t *shipments_arr, size_t total_shipments, - Vehicle_t *vehicles_arr, size_t total_vehicles, - Matrix_cell_t *matrix_cells_arr, size_t total_cells, - Time_multipliers_t *multipliers_arr, size_t total_multipliers, - - - double factor, - int max_cycles, - int64_t execution_date, - - bool check_triangle_inequality, - bool subdivide, - bool subdivide_by_vehicle, - - Short_vehicle_rt **return_tuples, - size_t *return_count, - - char **log_msg, - char **notice_msg, - char **err_msg) { - std::ostringstream log; - std::ostringstream notice; - std::ostringstream err; - try { - /* - * verify preconditions - */ - pgassert(!(*log_msg)); - pgassert(!(*notice_msg)); - pgassert(!(*err_msg)); - pgassert(total_shipments); - pgassert(total_vehicles); - pgassert(total_cells); - pgassert(*return_count == 0); - pgassert(!(*return_tuples)); - - *return_tuples = nullptr; - *return_count = 0; - - Identifiers node_ids; - Identifiers shipments_in_stops; - - /* - * Remove vehicles not going to be optimized and sort remaining vehicles - * 1. sort by id - * 2. remove duplicates - * - data comes from query that could possibly give a duplicate - * 3. remove vehicles that closes(end) before the execution time - */ - std::sort(vehicles_arr, vehicles_arr + total_vehicles, - [](const Vehicle_t& lhs, const Vehicle_t& rhs){return lhs.id < rhs.id;}); - - total_vehicles = static_cast(std::distance(vehicles_arr, - std::unique(vehicles_arr, vehicles_arr + total_vehicles, - [&](const Vehicle_t& lhs, const Vehicle_t& rhs){return lhs.id == rhs.id;}))); - - total_vehicles = static_cast(std::distance(vehicles_arr, - std::remove_if(vehicles_arr, vehicles_arr + total_vehicles, - [&](const Vehicle_t& v){return v.end_close_t < execution_date;}))); - - /* - * Remove shipments not involved in optimization - * 1. get the shipments on the stops of the vehicles - * - getting the node_ids in the same cycle - * 2. Remove duplicates - * 2. Remove shipments not on the stops - */ - for (size_t i = 0; i < total_vehicles; ++i) { - node_ids += vehicles_arr[i].start_node_id; - node_ids += vehicles_arr[i].end_node_id; - for (size_t j = 0; j < vehicles_arr[i].stops_size; ++j) { - shipments_in_stops += vehicles_arr[i].stops[j]; - } - } + Orders_t *shipments_arr, size_t total_shipments, + Vehicle_t *vehicles_arr, size_t total_vehicles, + Matrix_cell_t *matrix_cells_arr, size_t total_cells, + Time_multipliers_t *multipliers_arr, size_t total_multipliers, + + + double factor, + int max_cycles, + int64_t execution_date, + + bool check_triangle_inequality, + bool subdivide, + bool subdivide_by_vehicle, + + Short_vehicle_rt **return_tuples, + size_t *return_count, + + char **log_msg, + char **notice_msg, + char **err_msg) { + using vrprouting::alloc; + using vrprouting::to_pg_msg; + + std::ostringstream log; + std::ostringstream notice; + std::ostringstream err; + try { + /* + * verify preconditions + */ + pgassert(!(*log_msg)); + pgassert(!(*notice_msg)); + pgassert(!(*err_msg)); + pgassert(total_shipments); + pgassert(total_vehicles); + pgassert(total_cells); + pgassert(*return_count == 0); + pgassert(!(*return_tuples)); + + *return_tuples = nullptr; + *return_count = 0; + + Identifiers node_ids; + Identifiers shipments_in_stops; + + /* + * Remove vehicles not going to be optimized and sort remaining vehicles + * 1. sort by id + * 2. remove duplicates + * - data comes from query that could possibly give a duplicate + * 3. remove vehicles that closes(end) before the execution time + */ + std::sort(vehicles_arr, vehicles_arr + total_vehicles, + [](const Vehicle_t& lhs, const Vehicle_t& rhs){return lhs.id < rhs.id;}); + + total_vehicles = static_cast(std::distance(vehicles_arr, + std::unique(vehicles_arr, vehicles_arr + total_vehicles, + [&](const Vehicle_t& lhs, const Vehicle_t& rhs){return lhs.id == rhs.id;}))); + + total_vehicles = static_cast(std::distance(vehicles_arr, + std::remove_if(vehicles_arr, vehicles_arr + total_vehicles, + [&](const Vehicle_t& v){return v.end_close_t < execution_date;}))); + + /* + * Remove shipments not involved in optimization + * 1. get the shipments on the stops of the vehicles + * - getting the node_ids in the same cycle + * 2. Remove duplicates + * 2. Remove shipments not on the stops + */ + for (size_t i = 0; i < total_vehicles; ++i) { + node_ids += vehicles_arr[i].start_node_id; + node_ids += vehicles_arr[i].end_node_id; + for (size_t j = 0; j < vehicles_arr[i].stops_size; ++j) { + shipments_in_stops += vehicles_arr[i].stops[j]; + } + } - std::sort(shipments_arr, shipments_arr + total_shipments, - [](const PickDeliveryOrders_t& lhs, const PickDeliveryOrders_t& rhs){return lhs.id < rhs.id;}); - - total_shipments = static_cast(std::distance(shipments_arr, - std::unique(shipments_arr, shipments_arr + total_shipments, - [&](const PickDeliveryOrders_t& lhs, const PickDeliveryOrders_t& rhs){return lhs.id == rhs.id;}))); - - total_shipments = static_cast(std::distance(shipments_arr, - std::remove_if(shipments_arr, shipments_arr + total_shipments, - [&](const PickDeliveryOrders_t& s){return !shipments_in_stops.has(s.id);}))); - - /* - * Verify shipments complete data - */ - if (shipments_in_stops.size() != total_shipments) { - for (size_t i = 0; i < total_shipments; ++i) { - shipments_in_stops -= shipments_arr[i].id; - } - std::ostringstream hint; - err << "Missing shipments for processing "; - hint << "Shipments missing: " << shipments_in_stops << log.str(); - *log_msg = pgr_msg(hint.str()); - *err_msg = pgr_msg(err.str()); - return; - } + std::sort(shipments_arr, shipments_arr + total_shipments, + [](const Orders_t& lhs, const Orders_t& rhs){return lhs.id < rhs.id;}); + + total_shipments = static_cast(std::distance(shipments_arr, + std::unique(shipments_arr, shipments_arr + total_shipments, + [&](const Orders_t& lhs, const Orders_t& rhs){return lhs.id == rhs.id;}))); + + total_shipments = static_cast(std::distance(shipments_arr, + std::remove_if(shipments_arr, shipments_arr + total_shipments, + [&](const Orders_t& s){return !shipments_in_stops.has(s.id);}))); + + /* + * Verify shipments complete data + */ + if (shipments_in_stops.size() != total_shipments) { + for (size_t i = 0; i < total_shipments; ++i) { + shipments_in_stops -= shipments_arr[i].id; + } + std::ostringstream hint; + err << "Missing shipments for processing "; + hint << "Shipments missing: " << shipments_in_stops << log.str(); + *log_msg = to_pg_msg(hint.str()); + *err_msg = to_pg_msg(err.str()); + return; + } - /* - * Finish getting the node ids involved on the process - */ - for (size_t i = 0; i < total_shipments; ++i) { - node_ids += shipments_arr[i].pick_node_id; - node_ids += shipments_arr[i].deliver_node_id; - } + /* + * Finish getting the node ids involved on the process + */ + for (size_t i = 0; i < total_shipments; ++i) { + node_ids += shipments_arr[i].pick_node_id; + node_ids += shipments_arr[i].deliver_node_id; + } - /* - * Dealing with time matrix: - * - Create the unique time matrix to be used for all optimizations - * - Verify matrix triangle inequality - * - Verify matrix cells preconditions - */ - vrprouting::problem::Matrix time_matrix( - matrix_cells_arr, total_cells, - multipliers_arr, total_multipliers, - node_ids, static_cast(factor)); - - if (check_triangle_inequality && !time_matrix.obeys_triangle_inequality()) { - log << "\nFixing Matrix that does not obey triangle inequality " - << time_matrix.fix_triangle_inequality() << " cycles used"; - - if (!time_matrix.obeys_triangle_inequality()) { - log << "\nMatrix Still does not obey triangle inequality "; - } - } + /* + * Dealing with time matrix: + * - Create the unique time matrix to be used for all optimizations + * - Verify matrix triangle inequality + * - Verify matrix cells preconditions + */ + vrprouting::problem::Matrix time_matrix( + matrix_cells_arr, total_cells, + multipliers_arr, total_multipliers, + node_ids, static_cast(factor)); + + if (check_triangle_inequality && !time_matrix.obeys_triangle_inequality()) { + log << "\nFixing Matrix that does not obey triangle inequality " + << time_matrix.fix_triangle_inequality() << " cycles used"; + + if (!time_matrix.obeys_triangle_inequality()) { + log << "\nMatrix Still does not obey triangle inequality "; + } + } - if (!time_matrix.has_no_infinity()) { - err << "\nAn Infinity value was found on the Matrix"; - *err_msg = pgr_msg(err.str()); - *log_msg = pgr_msg(log.str()); - return; - } + if (!time_matrix.has_no_infinity()) { + err << "\nAn Infinity value was found on the Matrix"; + *err_msg = to_pg_msg(err.str()); + *log_msg = to_pg_msg(log.str()); + return; + } - /* - * get the solution - */ - auto solution = subdivide? - subdivide_processing( - shipments_arr, total_shipments, - vehicles_arr, total_vehicles, - time_matrix, - max_cycles, execution_date, - subdivide_by_vehicle, - log) : - one_processing( - shipments_arr, total_shipments, - vehicles_arr, total_vehicles, {}, - time_matrix, - max_cycles, execution_date); - - /* - * Prepare results - */ - if (!solution.empty()) { - (*return_tuples) = pgr_alloc(total_shipments * 2, (*return_tuples)); - - size_t seq = 0; - for (const auto &row : solution) { - for (const auto &o_id : row.stops) { - (*return_tuples)[seq].vehicle_id = row.id; - (*return_tuples)[seq].order_id = o_id; - ++seq; + /* + * get the solution + */ + auto solution = subdivide? + subdivide_processing( + shipments_arr, total_shipments, + vehicles_arr, total_vehicles, + time_matrix, + max_cycles, execution_date, + subdivide_by_vehicle, + log) : + one_processing( + shipments_arr, total_shipments, + vehicles_arr, total_vehicles, {}, + time_matrix, + max_cycles, execution_date); + + /* + * Prepare results + */ + if (!solution.empty()) { + (*return_tuples) = alloc(total_shipments * 2, (*return_tuples)); + + size_t seq = 0; + for (const auto &row : solution) { + for (const auto &o_id : row.stops) { + (*return_tuples)[seq].vehicle_id = row.id; + (*return_tuples)[seq].order_id = o_id; + ++seq; + } + } } - } - } - (*return_count) = total_shipments * 2; - - pgassert(*err_msg == nullptr); - *log_msg = log.str().empty()? - nullptr : - pgr_msg(log.str()); - *notice_msg = notice.str().empty()? - nullptr : - pgr_msg(notice.str()); - } catch (AssertFailedException &except) { - err << except.what() << log.str(); - *err_msg = pgr_msg(err.str()); - } catch (std::exception& except) { - err << except.what() << log.str(); - *err_msg = pgr_msg(err.str()); - } catch (const std::pair& ex) { - err << ex.first; - log.str(""); - log.clear(); - log << ex.second; - *err_msg = pgr_msg(err.str().c_str()); - *log_msg = pgr_msg(log.str().c_str()); - } catch(...) { - err << "Caught unknown exception!" << log.str(); - *err_msg = pgr_msg(err.str()); - } + (*return_count) = total_shipments * 2; + + pgassert(*err_msg == nullptr); + *log_msg = log.str().empty()? + nullptr : + to_pg_msg(log.str()); + *notice_msg = notice.str().empty()? + nullptr : + to_pg_msg(notice.str()); + } catch (AssertFailedException &except) { + err << except.what() << log.str(); + *err_msg = to_pg_msg(err.str()); + } catch (std::exception& except) { + err << except.what() << log.str(); + *err_msg = to_pg_msg(err.str()); + } catch (const std::pair& ex) { + err << ex.first; + log.str(""); + log.clear(); + log << ex.second; + *err_msg = to_pg_msg(err.str().c_str()); + *log_msg = to_pg_msg(log.str().c_str()); + } catch(...) { + err << "Caught unknown exception!" << log.str(); + *err_msg = to_pg_msg(err.str()); + } } diff --git a/src/pgr_pickDeliver/pgr_pickDeliverEuclidean_driver.cpp b/src/pgr_pickDeliver/pgr_pickDeliverEuclidean_driver.cpp index 57bceae1b..d4dfc5a59 100644 --- a/src/pgr_pickDeliver/pgr_pickDeliverEuclidean_driver.cpp +++ b/src/pgr_pickDeliver/pgr_pickDeliverEuclidean_driver.cpp @@ -48,244 +48,247 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. namespace { vrprouting::problem::Solution get_initial_solution(vrprouting::problem::PickDeliver* problem_ptr, int m_initial_id) { - using Solution = vrprouting::problem::Solution; - using Initial_solution = vrprouting::initialsol::simple::Initial_solution; - using Initials_code = vrprouting::initialsol::simple::Initials_code; - Solution m_solutions(problem_ptr); - if (m_initial_id == 0) { - for (int i = 1; i < 7; ++i) { - if (i == 1) { - m_solutions = Initial_solution((Initials_code)i, problem_ptr); - } else { - auto new_sol = Initial_solution((Initials_code)i, problem_ptr); - m_solutions = (new_sol < m_solutions)? new_sol : m_solutions; - } + using Solution = vrprouting::problem::Solution; + using Initial_solution = vrprouting::initialsol::simple::Initial_solution; + using Initials_code = vrprouting::initialsol::simple::Initials_code; + Solution m_solutions(problem_ptr); + if (m_initial_id == 0) { + for (int i = 1; i < 7; ++i) { + if (i == 1) { + m_solutions = Initial_solution((Initials_code)i, problem_ptr); + } else { + auto new_sol = Initial_solution((Initials_code)i, problem_ptr); + m_solutions = (new_sol < m_solutions)? new_sol : m_solutions; + } + } + } else { + m_solutions = Initial_solution((Initials_code)m_initial_id, problem_ptr); } - } else { - m_solutions = Initial_solution((Initials_code)m_initial_id, problem_ptr); - } - return m_solutions; + return m_solutions; } bool are_shipments_ok( - PickDeliveryOrders_t *customers_arr, - size_t total_customers, - std::string *err_string, - std::string *hint_string) { - /** - * - demand > 0 (the type is unsigned so no need to check for negative values, only for it to be non 0 - * - pick_service_t >=0 - * - drop_service_t >=0 - * - p_open <= p_close - * - d_open <= d_close - */ - for (size_t i = 0; i < total_customers; ++i) { - if (customers_arr[i].demand == 0) { - *err_string = "Unexpected zero value found on column 'demand' of shipments"; - *hint_string = "Check shipment id #:" + std::to_string(customers_arr[i].id); - return false; - } - - if (customers_arr[i].pick_service_t < 0) { - *err_string = "Unexpected negative value found on column 'p_service_t' of shipments"; - *hint_string = "Check shipment id #:" + std::to_string(customers_arr[i].id); - return false; - } - - if (customers_arr[i].deliver_service_t < 0) { - *err_string = "Unexpected negative value found on column 'd_service_t' of shipments"; - *hint_string = "Check shipment id #:" + std::to_string(customers_arr[i].id); - return false; - } - - if (customers_arr[i].pick_open_t > customers_arr[i].pick_close_t) { - *err_string = "Unexpected pickup time windows found on shipments"; - *hint_string = "Check shipment id #:" + std::to_string(customers_arr[i].id); - return false; - } - - if (customers_arr[i].deliver_open_t > customers_arr[i].deliver_close_t) { - *err_string = "Unexpected delivery time windows found on shipments"; - *hint_string = "Check shipment id #:" + std::to_string(customers_arr[i].id); - return false; + Orders_t *customers_arr, + size_t total_customers, + std::string *err_string, + std::string *hint_string) { + /** + * - demand > 0 (the type is unsigned so no need to check for negative values, only for it to be non 0 + * - pick_service_t >=0 + * - drop_service_t >=0 + * - p_open <= p_close + * - d_open <= d_close + */ + for (size_t i = 0; i < total_customers; ++i) { + if (customers_arr[i].demand == 0) { + *err_string = "Unexpected zero value found on column 'demand' of shipments"; + *hint_string = "Check shipment id #:" + std::to_string(customers_arr[i].id); + return false; + } + + if (customers_arr[i].pick_service_t < 0) { + *err_string = "Unexpected negative value found on column 'p_service_t' of shipments"; + *hint_string = "Check shipment id #:" + std::to_string(customers_arr[i].id); + return false; + } + + if (customers_arr[i].deliver_service_t < 0) { + *err_string = "Unexpected negative value found on column 'd_service_t' of shipments"; + *hint_string = "Check shipment id #:" + std::to_string(customers_arr[i].id); + return false; + } + + if (customers_arr[i].pick_open_t > customers_arr[i].pick_close_t) { + *err_string = "Unexpected pickup time windows found on shipments"; + *hint_string = "Check shipment id #:" + std::to_string(customers_arr[i].id); + return false; + } + + if (customers_arr[i].deliver_open_t > customers_arr[i].deliver_close_t) { + *err_string = "Unexpected delivery time windows found on shipments"; + *hint_string = "Check shipment id #:" + std::to_string(customers_arr[i].id); + return false; + } } - } - return true; + return true; } } // namespace void do_pgr_pickDeliverEuclidean( - PickDeliveryOrders_t *customers_arr, - size_t total_customers, - - Vehicle_t *vehicles_arr, - size_t total_vehicles, - - double factor, - int max_cycles, - int initial_solution_id, - - Solution_rt **return_tuples, - size_t *return_count, - - char **log_msg, - char **notice_msg, - char **err_msg) { - std::ostringstream log; - std::ostringstream notice; - std::ostringstream err; - try { - *return_tuples = nullptr; - *return_count = 0; - std::string err_string; - std::string hint_string; - if (!are_shipments_ok(customers_arr, total_customers, &err_string, &hint_string)) { - *err_msg = pgr_msg(err_string.c_str()); - *log_msg = pgr_msg(hint_string.c_str()); - return; - } + Orders_t *customers_arr, + size_t total_customers, - /* - * transform to C++ containers - */ - std::vector orders( - customers_arr, customers_arr + total_customers); - std::vector vehicles( - vehicles_arr, vehicles_arr + total_vehicles); - - std::map, Id> matrix_data; - - for (const auto &o : orders) { - pgassert(o.pick_node_id == 0); - pgassert(o.deliver_node_id == 0); - matrix_data[std::pair(o.pick_x, o.pick_y)] = 0; - matrix_data[std::pair(o.deliver_x, o.deliver_y)] = 0; - } + Vehicle_t *vehicles_arr, + size_t total_vehicles, - for (const auto &v : vehicles) { - matrix_data[std::pair(v.start_x, v.start_y)] = 0; - matrix_data[std::pair(v.end_x, v.end_y)] = 0; - } + double factor, + int max_cycles, + int initial_solution_id, - Identifiers unique_ids; - /* - * Data does not have ids for the locations' - */ - Id id(0); - for (auto &e : matrix_data) { - e.second = id++; - } + Solution_rt **return_tuples, + size_t *return_count, - for (const auto &e : matrix_data) { - unique_ids += e.second; - log << e.second << "(" << e.first.first << "," << e.first.second << ")\n"; - } - - for (size_t i = 0; i < total_customers; ++i) { - customers_arr[i].pick_node_id = - matrix_data[std::pair(customers_arr[i].pick_x, customers_arr[i].pick_y)]; - - customers_arr[i].deliver_node_id = - matrix_data[std::pair(customers_arr[i].deliver_x, customers_arr[i].deliver_y)]; - } - for (auto &v : vehicles) { - v.start_node_id = matrix_data[std::pair(v.start_x, v.start_y)]; - v.end_node_id = matrix_data[std::pair(v.end_x, v.end_y)]; - } + char **log_msg, + char **notice_msg, + char **err_msg) { + using vrprouting::alloc; + using vrprouting::to_pg_msg; - vrprouting::problem::Matrix cost_matrix(matrix_data, static_cast(factor)); - - log << "Initialize problem\n"; - vrprouting::problem::PickDeliver pd_problem( - customers_arr, total_customers, - vehicles_arr, total_vehicles, - cost_matrix); - - err << pd_problem.msg.get_error(); - if (!err.str().empty()) { - log.str(""); - log.clear(); - log << pd_problem.msg.get_error(); - log << pd_problem.msg.get_log(); - *log_msg = pgr_msg(log.str().c_str()); - *err_msg = pgr_msg(err.str().c_str()); - return; - } - log << pd_problem.msg.get_log(); - log << "Finish Reading data\n"; + std::ostringstream log; + std::ostringstream notice; + std::ostringstream err; + try { + *return_tuples = nullptr; + *return_count = 0; + std::string err_string; + std::string hint_string; + if (!are_shipments_ok(customers_arr, total_customers, &err_string, &hint_string)) { + *err_msg = to_pg_msg(err_string.c_str()); + *log_msg = to_pg_msg(hint_string.c_str()); + return; + } + + /* + * transform to C++ containers + */ + std::vector orders( + customers_arr, customers_arr + total_customers); + std::vector vehicles( + vehicles_arr, vehicles_arr + total_vehicles); + + std::map, Id> matrix_data; + + for (const auto &o : orders) { + pgassert(o.pick_node_id == 0); + pgassert(o.deliver_node_id == 0); + matrix_data[std::pair(o.pick_x, o.pick_y)] = 0; + matrix_data[std::pair(o.deliver_x, o.deliver_y)] = 0; + } + + for (const auto &v : vehicles) { + matrix_data[std::pair(v.start_x, v.start_y)] = 0; + matrix_data[std::pair(v.end_x, v.end_y)] = 0; + } + + Identifiers unique_ids; + /* + * Data does not have ids for the locations' + */ + Id id(0); + for (auto &e : matrix_data) { + e.second = id++; + } + + for (const auto &e : matrix_data) { + unique_ids += e.second; + log << e.second << "(" << e.first.first << "," << e.first.second << ")\n"; + } + + for (size_t i = 0; i < total_customers; ++i) { + customers_arr[i].pick_node_id = + matrix_data[std::pair(customers_arr[i].pick_x, customers_arr[i].pick_y)]; + + customers_arr[i].deliver_node_id = + matrix_data[std::pair(customers_arr[i].deliver_x, customers_arr[i].deliver_y)]; + } + for (auto &v : vehicles) { + v.start_node_id = matrix_data[std::pair(v.start_x, v.start_y)]; + v.end_node_id = matrix_data[std::pair(v.end_x, v.end_y)]; + } + + vrprouting::problem::Matrix cost_matrix(matrix_data, static_cast(factor)); + + log << "Initialize problem\n"; + vrprouting::problem::PickDeliver pd_problem( + customers_arr, total_customers, + vehicles_arr, total_vehicles, + cost_matrix); + + err << pd_problem.msg.get_error(); + if (!err.str().empty()) { + log.str(""); + log.clear(); + log << pd_problem.msg.get_error(); + log << pd_problem.msg.get_log(); + *log_msg = to_pg_msg(log.str().c_str()); + *err_msg = to_pg_msg(err.str().c_str()); + return; + } + log << pd_problem.msg.get_log(); + log << "Finish Reading data\n"; #if 0 - try { + try { #endif - auto sol = get_initial_solution(&pd_problem, initial_solution_id); - using Optimize = vrprouting::optimizers::simple::Optimize; - using Initials_code = vrprouting::initialsol::simple::Initials_code; - sol = Optimize(sol, static_cast(max_cycles), (Initials_code)initial_solution_id); + auto sol = get_initial_solution(&pd_problem, initial_solution_id); + using Optimize = vrprouting::optimizers::simple::Optimize; + using Initials_code = vrprouting::initialsol::simple::Initials_code; + sol = Optimize(sol, static_cast(max_cycles), (Initials_code)initial_solution_id); #if 0 + } catch (AssertFailedException &except) { + log << pd_problem.msg.get_log(); + throw; + } catch(...) { + log << "Caught unknown exception!"; + throw; + } +#endif + log << pd_problem.msg.get_log(); + log << "Finish solve\n"; + + auto solution = sol.get_postgres_result(); + log << pd_problem.msg.get_log(); + log << "solution size: " << solution.size() << "\n"; + + + if (!solution.empty()) { + (*return_tuples) = alloc(solution.size(), (*return_tuples)); + int seq = 0; + for (const auto &row : solution) { + (*return_tuples)[seq] = row; + ++seq; + } + } + (*return_count) = solution.size(); + + log << pd_problem.msg.get_log(); + + pgassert(*err_msg == NULL); + *log_msg = log.str().empty()? + nullptr : + to_pg_msg(log.str().c_str()); + *notice_msg = notice.str().empty()? + nullptr : + to_pg_msg(notice.str().c_str()); } catch (AssertFailedException &except) { - log << pd_problem.msg.get_log(); - throw; + if (*return_tuples) free(*return_tuples); + (*return_count) = 0; + err << except.what(); + *err_msg = to_pg_msg(err.str().c_str()); + *log_msg = to_pg_msg(log.str().c_str()); + } catch (std::exception& except) { + if (*return_tuples) free(*return_tuples); + (*return_count) = 0; + err << except.what(); + *err_msg = to_pg_msg(err.str().c_str()); + *log_msg = to_pg_msg(log.str().c_str()); + } catch (const std::pair& ex) { + (*return_count) = 0; + err << ex.first; + log.str(""); + log.clear(); + log << ex.second; + *err_msg = to_pg_msg(err.str().c_str()); + *log_msg = to_pg_msg(log.str().c_str()); } catch(...) { - log << "Caught unknown exception!"; - throw; - } -#endif - log << pd_problem.msg.get_log(); - log << "Finish solve\n"; - - auto solution = sol.get_postgres_result(); - log << pd_problem.msg.get_log(); - log << "solution size: " << solution.size() << "\n"; - - - if (!solution.empty()) { - (*return_tuples) = pgr_alloc(solution.size(), (*return_tuples)); - int seq = 0; - for (const auto &row : solution) { - (*return_tuples)[seq] = row; - ++seq; - } + if (*return_tuples) free(*return_tuples); + (*return_count) = 0; + err << "Caught unknown exception!"; + *err_msg = to_pg_msg(err.str().c_str()); + *log_msg = to_pg_msg(log.str().c_str()); } - (*return_count) = solution.size(); - - log << pd_problem.msg.get_log(); - - pgassert(*err_msg == NULL); - *log_msg = log.str().empty()? - nullptr : - pgr_msg(log.str().c_str()); - *notice_msg = notice.str().empty()? - nullptr : - pgr_msg(notice.str().c_str()); - } catch (AssertFailedException &except) { - if (*return_tuples) free(*return_tuples); - (*return_count) = 0; - err << except.what(); - *err_msg = pgr_msg(err.str().c_str()); - *log_msg = pgr_msg(log.str().c_str()); - } catch (std::exception& except) { - if (*return_tuples) free(*return_tuples); - (*return_count) = 0; - err << except.what(); - *err_msg = pgr_msg(err.str().c_str()); - *log_msg = pgr_msg(log.str().c_str()); - } catch (const std::pair& ex) { - (*return_count) = 0; - err << ex.first; - log.str(""); - log.clear(); - log << ex.second; - *err_msg = pgr_msg(err.str().c_str()); - *log_msg = pgr_msg(log.str().c_str()); - } catch(...) { - if (*return_tuples) free(*return_tuples); - (*return_count) = 0; - err << "Caught unknown exception!"; - *err_msg = pgr_msg(err.str().c_str()); - *log_msg = pgr_msg(log.str().c_str()); - } } diff --git a/src/pgr_pickDeliver/pgr_pickDeliver_driver.cpp b/src/pgr_pickDeliver/pgr_pickDeliver_driver.cpp index 1b5932b4c..c47ed1c57 100644 --- a/src/pgr_pickDeliver/pgr_pickDeliver_driver.cpp +++ b/src/pgr_pickDeliver/pgr_pickDeliver_driver.cpp @@ -49,31 +49,31 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. namespace { vrprouting::problem::Solution -get_initial_solution(vrprouting::problem::PickDeliver* problem_ptr, int m_initial_id) { - using Solution = vrprouting::problem::Solution; - using Initial_solution = vrprouting::initialsol::simple::Initial_solution; - using Initials_code = vrprouting::initialsol::simple::Initials_code; - Solution m_solutions(problem_ptr); - if (m_initial_id == 0) { - for (int i = 1; i < 7; ++i) { - if (i == 1) { - m_solutions = Initial_solution((Initials_code)i, problem_ptr); - } else { - auto new_sol = Initial_solution((Initials_code)i, problem_ptr); - m_solutions = (new_sol < m_solutions)? new_sol : m_solutions; + get_initial_solution(vrprouting::problem::PickDeliver* problem_ptr, int m_initial_id) { + using Solution = vrprouting::problem::Solution; + using Initial_solution = vrprouting::initialsol::simple::Initial_solution; + using Initials_code = vrprouting::initialsol::simple::Initials_code; + Solution m_solutions(problem_ptr); + if (m_initial_id == 0) { + for (int i = 1; i < 7; ++i) { + if (i == 1) { + m_solutions = Initial_solution((Initials_code)i, problem_ptr); + } else { + auto new_sol = Initial_solution((Initials_code)i, problem_ptr); + m_solutions = (new_sol < m_solutions)? new_sol : m_solutions; + } } + } else { + m_solutions = Initial_solution((Initials_code)m_initial_id, problem_ptr); } - } else { - m_solutions = Initial_solution((Initials_code)m_initial_id, problem_ptr); - } - return m_solutions; -} + return m_solutions; + } } // namespace void do_pgr_pickDeliver( - struct PickDeliveryOrders_t customers_arr[], + struct Orders_t customers_arr[], size_t total_customers, Vehicle_t *vehicles_arr, @@ -92,6 +92,9 @@ do_pgr_pickDeliver( char **log_msg, char **notice_msg, char **err_msg) { + using vrprouting::alloc; + using vrprouting::to_pg_msg; + std::ostringstream log; std::ostringstream notice; std::ostringstream err; @@ -152,7 +155,7 @@ do_pgr_pickDeliver( for (const auto &v : vehicles) { if (v.start_node_id != depot_node && v.end_node_id != depot_node) { err << "All vehicles must depart & arrive to same node"; - *err_msg = pgr_msg(err.str().c_str()); + *err_msg = to_pg_msg(err.str().c_str()); return; } } @@ -163,7 +166,7 @@ do_pgr_pickDeliver( for (size_t i = 0; i < total_customers; ++i) { if (customers_arr[i].pick_node_id != depot_node) { err << "All orders must be picked at depot"; - *err_msg = pgr_msg(err.str().c_str()); + *err_msg = to_pg_msg(err.str().c_str()); return; } } @@ -172,7 +175,7 @@ do_pgr_pickDeliver( if (!time_matrix.has_no_infinity()) { err << "An Infinity value was found on the Matrix. Might be missing information of a node"; - *err_msg = pgr_msg(err.str().c_str()); + *err_msg = to_pg_msg(err.str().c_str()); return; } @@ -187,8 +190,8 @@ do_pgr_pickDeliver( err << pd_problem.msg.get_error(); if (!err.str().empty()) { log << pd_problem.msg.get_log(); - *log_msg = pgr_msg(log.str().c_str()); - *err_msg = pgr_msg(err.str().c_str()); + *log_msg = to_pg_msg(log.str().c_str()); + *err_msg = to_pg_msg(err.str().c_str()); return; } log << pd_problem.msg.get_log(); @@ -198,7 +201,7 @@ do_pgr_pickDeliver( #if 0 try { #endif - using Initials_code = vrprouting::initialsol::simple::Initials_code; + using Initials_code = vrprouting::initialsol::simple::Initials_code; auto sol = get_initial_solution(&pd_problem, initial_solution_id); using Optimize = vrprouting::optimizers::simple::Optimize; sol = Optimize(sol, static_cast(max_cycles), (Initials_code)initial_solution_id); @@ -224,7 +227,7 @@ do_pgr_pickDeliver( if (!solution.empty()) { - (*return_tuples) = pgr_alloc(solution.size(), (*return_tuples)); + (*return_tuples) = alloc(solution.size(), (*return_tuples)); int seq = 0; for (const auto &row : solution) { (*return_tuples)[seq] = row; @@ -236,39 +239,39 @@ do_pgr_pickDeliver( pgassert(*err_msg == NULL); *log_msg = log.str().empty()? nullptr : - pgr_msg(log.str().c_str()); + to_pg_msg(log.str().c_str()); *notice_msg = notice.str().empty()? nullptr : - pgr_msg(notice.str().c_str()); + to_pg_msg(notice.str().c_str()); } catch (AssertFailedException &except) { if (*return_tuples) free(*return_tuples); (*return_count) = 0; err << except.what(); - *err_msg = pgr_msg(err.str().c_str()); - *log_msg = pgr_msg(log.str().c_str()); + *err_msg = to_pg_msg(err.str().c_str()); + *log_msg = to_pg_msg(log.str().c_str()); } catch (std::exception& except) { if (*return_tuples) free(*return_tuples); (*return_count) = 0; err << except.what(); - *err_msg = pgr_msg(err.str().c_str()); - *log_msg = pgr_msg(log.str().c_str()); + *err_msg = to_pg_msg(err.str().c_str()); + *log_msg = to_pg_msg(log.str().c_str()); } catch (const std::pair& ex) { (*return_count) = 0; err << ex.first; log << ex.second; - *err_msg = pgr_msg(err.str().c_str()); - *log_msg = pgr_msg(log.str().c_str()); + *err_msg = to_pg_msg(err.str().c_str()); + *log_msg = to_pg_msg(log.str().c_str()); } catch (const std::pair& ex) { (*return_count) = 0; err << ex.first; log << "FOOOO missing on matrix: id = " << ex.second; - *err_msg = pgr_msg(err.str().c_str()); - *log_msg = pgr_msg(log.str().c_str()); + *err_msg = to_pg_msg(err.str().c_str()); + *log_msg = to_pg_msg(log.str().c_str()); } catch(...) { if (*return_tuples) free(*return_tuples); (*return_count) = 0; err << "Caught unknown exception!"; - *err_msg = pgr_msg(err.str().c_str()); - *log_msg = pgr_msg(log.str().c_str()); + *err_msg = to_pg_msg(err.str().c_str()); + *log_msg = to_pg_msg(log.str().c_str()); } } diff --git a/src/pgr_pickDeliver/pickDeliver.c b/src/pgr_pickDeliver/pickDeliver.c index c9faf45af..db39e4390 100644 --- a/src/pgr_pickDeliver/pickDeliver.c +++ b/src/pgr_pickDeliver/pickDeliver.c @@ -83,9 +83,9 @@ process( return; } - pgr_SPI_connect(); + vrp_SPI_connect(); - PickDeliveryOrders_t *pd_orders_arr = NULL; + Orders_t *pd_orders_arr = NULL; size_t total_pd_orders = 0; get_shipments_raw(pd_orders_sql, &pd_orders_arr, &total_pd_orders); @@ -99,7 +99,7 @@ process( pfree(pd_orders_arr); pd_orders_arr = NULL; } - pgr_SPI_finish(); + vrp_SPI_finish(); ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("No orders found"))); @@ -125,7 +125,7 @@ process( pfree(vehicles_arr); vehicles_arr = NULL; } - pgr_SPI_finish(); + vrp_SPI_finish(); ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("No vehicles found"))); @@ -209,7 +209,7 @@ process( ereport(WARNING, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("No matrix found"))); - pgr_SPI_finish(); + vrp_SPI_finish(); return; } @@ -248,18 +248,9 @@ process( (*result_count) = 0; (*result_tuples) = NULL; } - pgr_global_report(log_msg, notice_msg, err_msg); + vrp_global_report(&log_msg, ¬ice_msg, &err_msg); /* freeing memory before return */ - if (log_msg) { - pfree(log_msg); log_msg = NULL; - } - if (notice_msg) { - pfree(notice_msg); notice_msg = NULL; - } - if (err_msg) { - pfree(err_msg); err_msg = NULL; - } if (pd_orders_arr) { pfree(pd_orders_arr); pd_orders_arr = NULL; } @@ -270,7 +261,7 @@ process( pfree(matrix_cells_arr); matrix_cells_arr = NULL; } - pgr_SPI_finish(); + vrp_SPI_finish(); } @@ -283,25 +274,14 @@ _vrp_pgr_pickdeliver(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; TupleDesc tuple_desc; - /**************************************************************************/ Solution_rt *result_tuples = 0; size_t result_count = 0; - /**************************************************************************/ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - /********************************************************************** - orders_sql TEXT, - vehicles_sql TEXT, - matrix_cell_sql TEXT, - factor FLOAT DEFAULT 1, - max_cycles INTEGER DEFAULT 10, - initial_sol INTEGER DEFAULT 4, - **********************************************************************/ - process( text_to_cstring(PG_GETARG_TEXT_P(0)), text_to_cstring(PG_GETARG_TEXT_P(1)), @@ -312,8 +292,6 @@ _vrp_pgr_pickdeliver(PG_FUNCTION_ARGS) { &result_tuples, &result_count); - /*********************************************************************/ - funcctx->max_calls = result_count; funcctx->user_fctx = result_tuples; if (get_call_result_type(fcinfo, NULL, &tuple_desc) @@ -339,24 +317,6 @@ _vrp_pgr_pickdeliver(PG_FUNCTION_ARGS) { bool* nulls; size_t call_cntr = funcctx->call_cntr; - /********************************************************************* - - OUT seq INTEGER, - OUT vehicle_number INTEGER, - OUT vehicle_id BIGINT, - OUT vehicle_seq INTEGER, - OUT order_id BIGINT, - OUT stop_type INT, - OUT cargo FLOAT, - OUT travel_time FLOAT, - OUT arrival_time FLOAT, - OUT wait_time FLOAT, - OUT service_time FLOAT, - OUT departure_time FLOAT - - *********************************************************************/ - - size_t numb = 13; values = palloc(numb * sizeof(Datum)); nulls = palloc(numb * sizeof(bool)); diff --git a/src/pgr_pickDeliver/pickDeliverEuclidean.c b/src/pgr_pickDeliver/pickDeliverEuclidean.c index fb69a3110..96b56c01e 100644 --- a/src/pgr_pickDeliver/pickDeliverEuclidean.c +++ b/src/pgr_pickDeliver/pickDeliverEuclidean.c @@ -79,10 +79,10 @@ process( return; } - pgr_SPI_connect(); + vrp_SPI_connect(); PGR_DBG("Load orders"); - struct PickDeliveryOrders_t *pd_orders_arr = NULL; + struct Orders_t *pd_orders_arr = NULL; size_t total_pd_orders = 0; get_shipments_euclidean(pd_orders_sql, &pd_orders_arr, &total_pd_orders); @@ -147,7 +147,7 @@ process( if (total_pd_orders == 0 || total_vehicles == 0) { (*result_count) = 0; (*result_tuples) = NULL; - pgr_SPI_finish(); + vrp_SPI_finish(); return; } PGR_DBG("Total %ld orders in query:", total_pd_orders); @@ -179,46 +179,27 @@ process( (*result_tuples) = NULL; } - pgr_global_report(log_msg, notice_msg, err_msg); + vrp_global_report(&log_msg, ¬ice_msg, &err_msg); - if (log_msg) pfree(log_msg); - if (notice_msg) pfree(notice_msg); - if (err_msg) pfree(err_msg); if (pd_orders_arr) pfree(pd_orders_arr); if (vehicles_arr) pfree(vehicles_arr); - pgr_SPI_finish(); + vrp_SPI_finish(); } -/* */ -/******************************************************************************/ PGDLLEXPORT Datum _vrp_pgr_pickdelivereuclidean(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; TupleDesc tuple_desc; - /**************************************************************************/ - /* MODIFY AS NEEDED */ - /* */ Solution_rt *result_tuples = 0; size_t result_count = 0; - /* */ - /**************************************************************************/ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - /**********************************************************************/ - /* MODIFY AS NEEDED */ - /* - orders_sql TEXT, - vehicles_sql INTEGER, - max_cycles INTEGER, - initial_id INTEGER, - **********************************************************************/ - PGR_DBG("Calling process"); process( text_to_cstring(PG_GETARG_TEXT_P(0)), @@ -229,9 +210,6 @@ _vrp_pgr_pickdelivereuclidean(PG_FUNCTION_ARGS) { &result_tuples, &result_count); - /* */ - /*********************************************************************/ - funcctx->max_calls = result_count; funcctx->user_fctx = result_tuples; if (get_call_result_type(fcinfo, NULL, &tuple_desc) @@ -257,19 +235,6 @@ _vrp_pgr_pickdelivereuclidean(PG_FUNCTION_ARGS) { bool* nulls; size_t call_cntr = funcctx->call_cntr; - /*********************************************************************/ - /* MODIFY!!!!! */ - /* This has to match you output otherwise the server crashes */ - /* - OUT seq INTEGER, - OUT vehicle_id INTEGER, - OUT vehicle_seq INTEGER, - OUT order_id BIGINT, - OUT cost FLOAT, - OUT agg_cost FLOAT - *********************************************************************/ - - size_t numb = 12; values = palloc(numb * sizeof(Datum)); nulls = palloc(numb * sizeof(bool)); diff --git a/src/pickDeliver/pickDeliver.c b/src/pickDeliver/pickDeliver.c index 97cd95107..9f94b000e 100644 --- a/src/pickDeliver/pickDeliver.c +++ b/src/pickDeliver/pickDeliver.c @@ -65,210 +65,202 @@ process( Solution_rt **result_tuples, size_t *result_count) { - /* - * Adjusting timestamp data to timezone UTC - */ - if (use_timestamps) { - execution_date = timestamp_without_timezone(execution_date); - } + /* + * Adjusting timestamp data to timezone UTC + */ + if (use_timestamps) { + execution_date = timestamp_without_timezone(execution_date); + } - PGR_DBG("execution_date: %ld ", execution_date); + PGR_DBG("execution_date: %ld ", execution_date); - //! [Factor must be postive] - if (factor <= 0) { - ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Illegal value in parameter: factor"), - errhint("Value found: %f <= 0", factor))); - } - //! [Factor must be postive] - - if (max_cycles < 0) { - ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Illegal value in parameter: max_cycles"), - errhint("Value found: %d <= 0", max_cycles))); - } - - pgr_SPI_connect(); + //! [Factor must be postive] + if (factor <= 0) { + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Illegal value in parameter: factor"), + errhint("Value found: %f <= 0", factor))); + } + //! [Factor must be postive] - PickDeliveryOrders_t *pd_orders_arr = NULL; - size_t total_pd_orders = 0; - if (use_timestamps) { - get_shipments(pd_orders_sql, &pd_orders_arr, &total_pd_orders); - } else { - get_shipments_raw(pd_orders_sql, &pd_orders_arr, &total_pd_orders); - } + if (max_cycles < 0) { + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Illegal value in parameter: max_cycles"), + errhint("Value found: %d <= 0", max_cycles))); + } - if (total_pd_orders == 0) { - (*result_count) = 0; - (*result_tuples) = NULL; + vrp_SPI_connect(); - /* freeing memory before return */ - if (pd_orders_arr) { - pfree(pd_orders_arr); pd_orders_arr = NULL; + Orders_t *pd_orders_arr = NULL; + size_t total_pd_orders = 0; + if (use_timestamps) { + get_shipments(pd_orders_sql, &pd_orders_arr, &total_pd_orders); + } else { + get_shipments_raw(pd_orders_sql, &pd_orders_arr, &total_pd_orders); } - pgr_SPI_finish(); - return; - } - - Vehicle_t *vehicles_arr = NULL; - size_t total_vehicles = 0; - if (use_timestamps) { - get_vehicles(vehicles_sql, &vehicles_arr, &total_vehicles, true); - } else { - get_vehicles_raw(vehicles_sql, &vehicles_arr, &total_vehicles, true); - } + if (total_pd_orders == 0) { + (*result_count) = 0; + (*result_tuples) = NULL; - if (total_vehicles == 0) { - (*result_count) = 0; - (*result_tuples) = NULL; + /* freeing memory before return */ + if (pd_orders_arr) { + pfree(pd_orders_arr); pd_orders_arr = NULL; + } - /* freeing memory before return */ - if (pd_orders_arr) { - pfree(pd_orders_arr); pd_orders_arr = NULL; + vrp_SPI_finish(); + return; } - if (vehicles_arr) { - pfree(vehicles_arr); vehicles_arr = NULL; + + Vehicle_t *vehicles_arr = NULL; + size_t total_vehicles = 0; + if (use_timestamps) { + get_vehicles(vehicles_sql, &vehicles_arr, &total_vehicles, true); + } else { + get_vehicles_raw(vehicles_sql, &vehicles_arr, &total_vehicles, true); } - ereport(WARNING, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("No vehicles found"))); + if (total_vehicles == 0) { + (*result_count) = 0; + (*result_tuples) = NULL; - pgr_SPI_finish(); - return; - } + /* freeing memory before return */ + if (pd_orders_arr) { + pfree(pd_orders_arr); pd_orders_arr = NULL; + } + if (vehicles_arr) { + pfree(vehicles_arr); vehicles_arr = NULL; + } - Time_multipliers_t *multipliers_arr = NULL; - size_t total_multipliers_arr = 0; - if (use_timestamps) { - PGR_DBG("get_timeMultipliers"); - get_timeMultipliers(multipliers_sql, &multipliers_arr, &total_multipliers_arr); - } else { - PGR_DBG("get_timeMultipliers_raw"); - get_timeMultipliers_raw(multipliers_sql, &multipliers_arr, &total_multipliers_arr); - } - - if (total_multipliers_arr == 0) { - ereport(WARNING, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("No matrix found"))); - (*result_count) = 0; - (*result_tuples) = NULL; + ereport(WARNING, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("No vehicles found"))); - /* freeing memory before return */ - if (pd_orders_arr) { - pfree(pd_orders_arr); pd_orders_arr = NULL; - } - if (vehicles_arr) { - pfree(vehicles_arr); vehicles_arr = NULL; - } - if (multipliers_arr) { - pfree(multipliers_arr); multipliers_arr = NULL; + vrp_SPI_finish(); + return; } - pgr_SPI_finish(); - return; - } - - Matrix_cell_t *matrix_cells_arr = NULL; - size_t total_cells = 0; - if (use_timestamps) { - get_matrixRows(matrix_sql, &matrix_cells_arr, &total_cells); - } else { - get_matrixRows_plain(matrix_sql, &matrix_cells_arr, &total_cells); - } - - if (total_cells == 0) { - (*result_count) = 0; - (*result_tuples) = NULL; - - /* freeing memory before return */ - if (pd_orders_arr) { - pfree(pd_orders_arr); pd_orders_arr = NULL; + Time_multipliers_t *multipliers_arr = NULL; + size_t total_multipliers_arr = 0; + if (use_timestamps) { + PGR_DBG("get_timeMultipliers"); + get_timeMultipliers(multipliers_sql, &multipliers_arr, &total_multipliers_arr); + } else { + PGR_DBG("get_timeMultipliers_raw"); + get_timeMultipliers_raw(multipliers_sql, &multipliers_arr, &total_multipliers_arr); } - if (vehicles_arr) { - pfree(vehicles_arr); vehicles_arr = NULL; + + if (total_multipliers_arr == 0) { + ereport(WARNING, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("No matrix found"))); + (*result_count) = 0; + (*result_tuples) = NULL; + + /* freeing memory before return */ + if (pd_orders_arr) { + pfree(pd_orders_arr); pd_orders_arr = NULL; + } + if (vehicles_arr) { + pfree(vehicles_arr); vehicles_arr = NULL; + } + if (multipliers_arr) { + pfree(multipliers_arr); multipliers_arr = NULL; + } + + vrp_SPI_finish(); + return; } - if (multipliers_arr) { - pfree(multipliers_arr); multipliers_arr = NULL; + + Matrix_cell_t *matrix_cells_arr = NULL; + size_t total_cells = 0; + if (use_timestamps) { + get_matrixRows(matrix_sql, &matrix_cells_arr, &total_cells); + } else { + get_matrixRows_plain(matrix_sql, &matrix_cells_arr, &total_cells); } - if (matrix_cells_arr) { - pfree(matrix_cells_arr); matrix_cells_arr = NULL; + + if (total_cells == 0) { + (*result_count) = 0; + (*result_tuples) = NULL; + + /* freeing memory before return */ + if (pd_orders_arr) { + pfree(pd_orders_arr); pd_orders_arr = NULL; + } + if (vehicles_arr) { + pfree(vehicles_arr); vehicles_arr = NULL; + } + if (multipliers_arr) { + pfree(multipliers_arr); multipliers_arr = NULL; + } + if (matrix_cells_arr) { + pfree(matrix_cells_arr); matrix_cells_arr = NULL; + } + + ereport(WARNING, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("No matrix found"))); + vrp_SPI_finish(); + return; } - ereport(WARNING, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("No matrix found"))); - pgr_SPI_finish(); - return; - } + PGR_DBG("Total %ld orders in query:", total_pd_orders); + PGR_DBG("Total %ld vehicles in query:", total_vehicles); + PGR_DBG("Total %ld matrix cells in query:", total_cells); + PGR_DBG("Total %ld time dependant multipliers:", total_multipliers_arr); - PGR_DBG("Total %ld orders in query:", total_pd_orders); - PGR_DBG("Total %ld vehicles in query:", total_vehicles); - PGR_DBG("Total %ld matrix cells in query:", total_cells); - PGR_DBG("Total %ld time dependant multipliers:", total_multipliers_arr); + clock_t start_t = clock(); + char *log_msg = NULL; + char *notice_msg = NULL; + char *err_msg = NULL; - clock_t start_t = clock(); - char *log_msg = NULL; - char *notice_msg = NULL; - char *err_msg = NULL; + do_pickDeliver( + pd_orders_arr, total_pd_orders, + vehicles_arr, total_vehicles, + matrix_cells_arr, total_cells, + multipliers_arr, total_multipliers_arr, - do_pickDeliver( - pd_orders_arr, total_pd_orders, - vehicles_arr, total_vehicles, - matrix_cells_arr, total_cells, - multipliers_arr, total_multipliers_arr, + optimize, + factor, + max_cycles, + stop_on_all_served, - optimize, - factor, - max_cycles, - stop_on_all_served, + execution_date, - execution_date, + result_tuples, + result_count, - result_tuples, - result_count, + &log_msg, + ¬ice_msg, + &err_msg); - &log_msg, - ¬ice_msg, - &err_msg); + time_msg("pgr_pickDeliver", start_t, clock()); - time_msg("pgr_pickDeliver", start_t, clock()); + if (err_msg && (*result_tuples)) { + pfree(*result_tuples); + (*result_count) = 0; + (*result_tuples) = NULL; + } - if (err_msg && (*result_tuples)) { - pfree(*result_tuples); - (*result_count) = 0; - (*result_tuples) = NULL; - } - pgr_global_report(log_msg, notice_msg, err_msg); + vrp_global_report(&log_msg, ¬ice_msg, &err_msg); - /* freeing memory before return */ - if (log_msg) { - pfree(log_msg); log_msg = NULL; - } - if (notice_msg) { - pfree(notice_msg); notice_msg = NULL; - } - if (err_msg) { - pfree(err_msg); err_msg = NULL; - } - if (pd_orders_arr) { - pfree(pd_orders_arr); pd_orders_arr = NULL; - } - if (vehicles_arr) { - pfree(vehicles_arr); vehicles_arr = NULL; - } - if (multipliers_arr) { - pfree(multipliers_arr); multipliers_arr = NULL; - } - if (matrix_cells_arr) { - pfree(matrix_cells_arr); matrix_cells_arr = NULL; - } + /* freeing memory before return */ + if (pd_orders_arr) { + pfree(pd_orders_arr); pd_orders_arr = NULL; + } + if (vehicles_arr) { + pfree(vehicles_arr); vehicles_arr = NULL; + } + if (multipliers_arr) { + pfree(multipliers_arr); multipliers_arr = NULL; + } + if (matrix_cells_arr) { + pfree(matrix_cells_arr); matrix_cells_arr = NULL; + } - pgr_SPI_finish(); + vrp_SPI_finish(); } @@ -281,10 +273,8 @@ _vrp_pickdeliver(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; TupleDesc tuple_desc; - /**************************************************************************/ Solution_rt *result_tuples = 0; size_t result_count = 0; - /**************************************************************************/ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; @@ -307,8 +297,6 @@ _vrp_pickdeliver(PG_FUNCTION_ARGS) { &result_tuples, &result_count); - /*********************************************************************/ - funcctx->max_calls = result_count; funcctx->user_fctx = result_tuples; if (get_call_result_type(fcinfo, NULL, &tuple_desc) @@ -361,8 +349,6 @@ _vrp_pickdeliver(PG_FUNCTION_ARGS) { values[14] = Int32GetDatum(result_tuples[call_cntr].cvTot); values[15] = Int32GetDatum(result_tuples[call_cntr].twvTot); - /*********************************************************************/ - tuple = heap_form_tuple(tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); @@ -378,7 +364,6 @@ _vrp_pickdeliver(PG_FUNCTION_ARGS) { SRF_RETURN_DONE(funcctx); } } -/******************************************************************************/ /** @@ -389,10 +374,8 @@ _vrp_pickdeliverraw(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; TupleDesc tuple_desc; - /**************************************************************************/ Solution_rt *result_tuples = 0; size_t result_count = 0; - /**************************************************************************/ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; @@ -415,8 +398,6 @@ _vrp_pickdeliverraw(PG_FUNCTION_ARGS) { &result_tuples, &result_count); - /*********************************************************************/ - funcctx->max_calls = result_count; funcctx->user_fctx = result_tuples; if (get_call_result_type(fcinfo, NULL, &tuple_desc) @@ -469,8 +450,6 @@ _vrp_pickdeliverraw(PG_FUNCTION_ARGS) { values[14] = Int32GetDatum(result_tuples[call_cntr].cvTot); values[15] = Int32GetDatum(result_tuples[call_cntr].twvTot); - /*********************************************************************/ - tuple = heap_form_tuple(tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); diff --git a/src/pickDeliver/pickDeliver_driver.cpp b/src/pickDeliver/pickDeliver_driver.cpp index 09c612cb6..8d8a68ea9 100644 --- a/src/pickDeliver/pickDeliver_driver.cpp +++ b/src/pickDeliver/pickDeliver_driver.cpp @@ -106,192 +106,195 @@ digraph G { */ void do_pickDeliver( - PickDeliveryOrders_t *customers_arr, size_t total_customers, - Vehicle_t *vehicles_arr, size_t total_vehicles, - Matrix_cell_t *matrix_cells_arr, size_t total_cells, - Time_multipliers_t *multipliers_arr, size_t total_multipliers, - - - bool optimize, - double factor, - int max_cycles, - bool stop_on_all_served, - int64_t execution_date, - - Solution_rt **return_tuples, - size_t *return_count, - - char **log_msg, - char **notice_msg, - char **err_msg) { - std::ostringstream log; - std::ostringstream notice; - std::ostringstream err; - try { - /* - * verify preconditions - */ - pgassert(!(*log_msg)); - pgassert(!(*notice_msg)); - pgassert(!(*err_msg)); - pgassert(total_customers); - pgassert(total_vehicles); - pgassert(total_cells); - pgassert(*return_count == 0); - pgassert(!(*return_tuples)); - log << "do_pickDeliver\n"; - - *return_tuples = nullptr; - *return_count = 0; - - Identifiers node_ids; - Identifiers order_ids; - - for (size_t i = 0; i < total_customers; ++i) { - node_ids += customers_arr[i].pick_node_id; - node_ids += customers_arr[i].deliver_node_id; - order_ids += customers_arr[i].id; - } + Orders_t *customers_arr, size_t total_customers, + Vehicle_t *vehicles_arr, size_t total_vehicles, + Matrix_cell_t *matrix_cells_arr, size_t total_cells, + Time_multipliers_t *multipliers_arr, size_t total_multipliers, + + + bool optimize, + double factor, + int max_cycles, + bool stop_on_all_served, + int64_t execution_date, + + Solution_rt **return_tuples, + size_t *return_count, + + char **log_msg, + char **notice_msg, + char **err_msg) { + using vrprouting::alloc; + using vrprouting::to_pg_msg; + + std::ostringstream log; + std::ostringstream notice; + std::ostringstream err; + try { + /* + * verify preconditions + */ + pgassert(!(*log_msg)); + pgassert(!(*notice_msg)); + pgassert(!(*err_msg)); + pgassert(total_customers); + pgassert(total_vehicles); + pgassert(total_cells); + pgassert(*return_count == 0); + pgassert(!(*return_tuples)); + log << "do_pickDeliver\n"; + + *return_tuples = nullptr; + *return_count = 0; + + Identifiers node_ids; + Identifiers order_ids; + + for (size_t i = 0; i < total_customers; ++i) { + node_ids += customers_arr[i].pick_node_id; + node_ids += customers_arr[i].deliver_node_id; + order_ids += customers_arr[i].id; + } - bool missing = false; - for (size_t i = 0; i < total_vehicles; ++i) { - auto vehicle = vehicles_arr[i]; - node_ids += vehicle.start_node_id; - node_ids += vehicle.end_node_id; - for (size_t j = 0; j < vehicle.stops_size; ++j) { - if (!order_ids.has(vehicle.stops[j])) { - if (!missing) err << "Order in 'stops' information missing"; - missing = true; - err << "Missing information of order " << vehicle.stops[j] << "\n"; + bool missing = false; + for (size_t i = 0; i < total_vehicles; ++i) { + auto vehicle = vehicles_arr[i]; + node_ids += vehicle.start_node_id; + node_ids += vehicle.end_node_id; + for (size_t j = 0; j < vehicle.stops_size; ++j) { + if (!order_ids.has(vehicle.stops[j])) { + if (!missing) err << "Order in 'stops' information missing"; + missing = true; + err << "Missing information of order " << vehicle.stops[j] << "\n"; + } + } + if (missing) { + *err_msg = to_pg_msg(err.str()); + return; + } } - } - if (missing) { - *err_msg = pgr_msg(err.str()); - return; - } - } - vrprouting::problem::Matrix cost_matrix( - matrix_cells_arr, total_cells, - multipliers_arr, total_multipliers, - node_ids, static_cast(factor)); + vrprouting::problem::Matrix cost_matrix( + matrix_cells_arr, total_cells, + multipliers_arr, total_multipliers, + node_ids, static_cast(factor)); #if 1 - /* - * Verify matrix triangle inequality - */ - if (!cost_matrix.obeys_triangle_inequality()) { - log << "[PickDeliver] Fixing Matrix that does not obey triangle inequality "; - log << cost_matrix.fix_triangle_inequality() << " cycles used"; - - if (!cost_matrix.obeys_triangle_inequality()) { - log << "[pickDeliver] Matrix Still does not obey triangle inequality "; - } - } + /* + * Verify matrix triangle inequality + */ + if (!cost_matrix.obeys_triangle_inequality()) { + log << "[PickDeliver] Fixing Matrix that does not obey triangle inequality "; + log << cost_matrix.fix_triangle_inequality() << " cycles used"; + + if (!cost_matrix.obeys_triangle_inequality()) { + log << "[pickDeliver] Matrix Still does not obey triangle inequality "; + } + } #endif - /* - * Verify matrix cells preconditions - */ - if (!cost_matrix.has_no_infinity()) { - err << "An Infinity value was found on the Matrix"; - *err_msg = pgr_msg(err.str()); - return; - } + /* + * Verify matrix cells preconditions + */ + if (!cost_matrix.has_no_infinity()) { + err << "An Infinity value was found on the Matrix"; + *err_msg = to_pg_msg(err.str()); + return; + } - log << "stop_on_all_served" << stop_on_all_served << "\n"; - log << "execution_date" << execution_date << "\n"; - log << "Initialize problem\n"; - /* - * Construct problem - */ - vrprouting::problem::PickDeliver pd_problem( - customers_arr, total_customers, - vehicles_arr, total_vehicles, - cost_matrix); - - err << pd_problem.msg.get_error(); - if (!err.str().empty()) { - log << pd_problem.msg.get_error(); - log << pd_problem.msg.get_log(); - *log_msg = pgr_msg(log.str()); - *err_msg = pgr_msg(err.str()); - return; - } - log << pd_problem.msg.get_log(); - pd_problem.msg.clear(); + log << "stop_on_all_served" << stop_on_all_served << "\n"; + log << "execution_date" << execution_date << "\n"; + log << "Initialize problem\n"; + /* + * Construct problem + */ + vrprouting::problem::PickDeliver pd_problem( + customers_arr, total_customers, + vehicles_arr, total_vehicles, + cost_matrix); + + err << pd_problem.msg.get_error(); + if (!err.str().empty()) { + log << pd_problem.msg.get_error(); + log << pd_problem.msg.get_log(); + *log_msg = to_pg_msg(log.str()); + *err_msg = to_pg_msg(err.str()); + return; + } + log << pd_problem.msg.get_log(); + pd_problem.msg.clear(); - log << "Finish Initialize problem\n"; + log << "Finish Initialize problem\n"; #if 0 - try { + try { #endif - /* - * get initial solutions - */ - using Initial_solution = vrprouting::initialsol::tabu::Initial_solution; - using Solution = vrprouting::problem::Solution; - auto sol = static_cast(Initial_solution(execution_date, optimize, &pd_problem)); - /* - * Solve (optimize) - */ - using Optimize = vrprouting::optimizers::tabu::Optimize; - sol = Optimize(sol, static_cast(max_cycles), stop_on_all_served, optimize); + /* + * get initial solutions + */ + using Initial_solution = vrprouting::initialsol::tabu::Initial_solution; + using Solution = vrprouting::problem::Solution; + auto sol = static_cast(Initial_solution(execution_date, optimize, &pd_problem)); + /* + * Solve (optimize) + */ + using Optimize = vrprouting::optimizers::tabu::Optimize; + sol = Optimize(sol, static_cast(max_cycles), stop_on_all_served, optimize); #if 0 - } catch (AssertFailedException &except) { - log << pd_problem.msg.get_log(); - throw; - } catch(...) { - log << "Caught unknown exception!"; - throw; - } + } catch (AssertFailedException &except) { + log << pd_problem.msg.get_log(); + throw; + } catch(...) { + log << "Caught unknown exception!"; + throw; + } #endif - log << pd_problem.msg.get_log(); - pd_problem.msg.clear(); - log << "Finish solve\n"; - - /* - * Prepare results - */ - auto solution = sol.get_postgres_result(); - log << pd_problem.msg.get_log(); - pd_problem.msg.clear(); - log << "solution size: " << solution.size() << "\n"; - - - if (!solution.empty()) { - (*return_tuples) = pgr_alloc(solution.size(), (*return_tuples)); - int seq = 0; - for (const auto &row : solution) { - (*return_tuples)[seq] = row; - ++seq; - } + log << pd_problem.msg.get_log(); + pd_problem.msg.clear(); + log << "Finish solve\n"; + + /* + * Prepare results + */ + auto solution = sol.get_postgres_result(); + log << pd_problem.msg.get_log(); + pd_problem.msg.clear(); + log << "solution size: " << solution.size() << "\n"; + + + if (!solution.empty()) { + (*return_tuples) = alloc(solution.size(), (*return_tuples)); + int seq = 0; + for (const auto &row : solution) { + (*return_tuples)[seq] = row; + ++seq; + } + } + (*return_count) = solution.size(); + + log << pd_problem.msg.get_log(); + + pgassert(*err_msg == nullptr); + *log_msg = log.str().empty()? + nullptr : + to_pg_msg(log.str()); + *notice_msg = notice.str().empty()? + nullptr : + to_pg_msg(notice.str()); + } catch (AssertFailedException &except) { + if (*return_tuples) free(*return_tuples); + (*return_count) = 0; + err << except.what() << log.str(); + *err_msg = to_pg_msg(err.str()); + } catch (std::exception& except) { + if (*return_tuples) free(*return_tuples); + (*return_count) = 0; + err << except.what() << log.str(); + *err_msg = to_pg_msg(err.str()); + } catch(...) { + if (*return_tuples) free(*return_tuples); + (*return_count) = 0; + err << "Caught unknown exception!" << log.str(); + *err_msg = to_pg_msg(err.str()); } - (*return_count) = solution.size(); - - log << pd_problem.msg.get_log(); - - pgassert(*err_msg == nullptr); - *log_msg = log.str().empty()? - nullptr : - pgr_msg(log.str()); - *notice_msg = notice.str().empty()? - nullptr : - pgr_msg(notice.str()); - } catch (AssertFailedException &except) { - if (*return_tuples) free(*return_tuples); - (*return_count) = 0; - err << except.what() << log.str(); - *err_msg = pgr_msg(err.str()); - } catch (std::exception& except) { - if (*return_tuples) free(*return_tuples); - (*return_count) = 0; - err << except.what() << log.str(); - *err_msg = pgr_msg(err.str()); - } catch(...) { - if (*return_tuples) free(*return_tuples); - (*return_count) = 0; - err << "Caught unknown exception!" << log.str(); - *err_msg = pgr_msg(err.str()); - } } diff --git a/src/problem/tw_node.cpp b/src/problem/tw_node.cpp index 80c1421f2..3cbf119f5 100644 --- a/src/problem/tw_node.cpp +++ b/src/problem/tw_node.cpp @@ -312,7 +312,7 @@ bool Tw_node::is_valid() const { */ Tw_node::Tw_node( size_t id, - const PickDeliveryOrders_t &data, + const Orders_t &data, const NodeType &type) : Identifier(id, data.pick_node_id), m_order(data.id), diff --git a/src/vroom/vroom.c b/src/vroom/vroom.c index 6bf69d300..0ba8dcf0b 100644 --- a/src/vroom/vroom.c +++ b/src/vroom/vroom.c @@ -65,186 +65,157 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. PGDLLEXPORT Datum _vrp_vroom(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(_vrp_vroom); -/** @brief Static function, loads the data from postgres to C types for further processing. - * - * It first connects the C function to the SPI manager. Then converts - * the postgres array to C array and loads the edges belonging to the graph - * in C types. Then it calls the function `do_vrp_vroom` defined - * in the `vroom_driver.h` file for further processing. - * Finally, it frees the memory and disconnects the C function to the SPI manager. - * - * @param jobs_sql SQL query describing the jobs - * @param jobs_tw_sql SQL query describing the time window for jobs - * @param shipments_sql SQL query describing the shipments - * @param shipments_tw_sql SQL query describing the time windows for shipment - * @param vehicles_sql SQL query describing the vehicles - * @param breaks_sql SQL query describing the driver breaks. - * @param breaks_tws_sql SQL query describing the time windows for break start. - * @param matrix_sql SQL query describing the cells of the cost matrix - * @param exploration_level Exploration level to use while solving. - * @param timeout Timeout value to stop the solving process. - * @param fn Value denoting the function used. - * @param is_plain Value denoting whether the plain/timestamp function is used. - * @param result_tuples the rows in the result - * @param result_count the count of rows in the result - * - * @returns void - */ static void process( - char *jobs_sql, - char *jobs_tws_sql, - char *shipments_sql, - char *shipments_tws_sql, - char *vehicles_sql, - char *breaks_sql, - char *breaks_tws_sql, - char *matrix_sql, - - int32_t exploration_level, - int32_t timeout, - int16_t fn, - bool is_plain, - - Vroom_rt **result_tuples, - size_t *result_count) { - clock_t start_loading = clock(); - pgr_SPI_connect(); - - (*result_tuples) = NULL; - (*result_count) = 0; - - Vroom_job_t *jobs = NULL; - size_t total_jobs = 0; - if (jobs_sql) { - get_vroom_jobs(jobs_sql, &jobs, &total_jobs, is_plain); - } + char *jobs_sql, + char *jobs_tws_sql, + char *shipments_sql, + char *shipments_tws_sql, + char *vehicles_sql, + char *breaks_sql, + char *breaks_tws_sql, + char *matrix_sql, + + int32_t exploration_level, + int32_t timeout, + int16_t fn, + bool is_plain, + + Vroom_rt **result_tuples, + size_t *result_count) { + clock_t start_loading = clock(); + vrp_SPI_connect(); - Vroom_shipment_t *shipments = NULL; - size_t total_shipments = 0; - if (shipments_sql) { - get_vroom_shipments(shipments_sql, &shipments, &total_shipments, is_plain); - } + (*result_tuples) = NULL; + (*result_count) = 0; + + Vroom_job_t *jobs = NULL; + size_t total_jobs = 0; + if (jobs_sql) { + get_vroom_jobs(jobs_sql, &jobs, &total_jobs, is_plain); + } + + Vroom_shipment_t *shipments = NULL; + size_t total_shipments = 0; + if (shipments_sql) { + get_vroom_shipments(shipments_sql, &shipments, &total_shipments, is_plain); + } - if (total_jobs == 0 && total_shipments == 0) { - if (fn == 0) { - ereport(WARNING, (errmsg("Insufficient data found on Jobs SQL and Shipments SQL query."), + if (total_jobs == 0 && total_shipments == 0) { + if (fn == 0) { + ereport(WARNING, (errmsg("Insufficient data found on Jobs SQL and Shipments SQL query."), errhint("%s, %s", jobs_sql, shipments_sql))); - } else if (fn == 1) { - ereport(WARNING, (errmsg("Insufficient data found on Jobs SQL query."), + } else if (fn == 1) { + ereport(WARNING, (errmsg("Insufficient data found on Jobs SQL query."), errhint("%s", jobs_sql))); - } else if (fn == 2) { - ereport(WARNING, (errmsg("Insufficient data found on Shipments SQL query."), + } else if (fn == 2) { + ereport(WARNING, (errmsg("Insufficient data found on Shipments SQL query."), errhint("%s", shipments_sql))); + } + (*result_count) = 0; + (*result_tuples) = NULL; + vrp_SPI_finish(); + return; } - (*result_count) = 0; - (*result_tuples) = NULL; - pgr_SPI_finish(); - return; - } - - Vroom_time_window_t *jobs_tws = NULL; - size_t total_jobs_tws = 0; - if (jobs_tws_sql) { - get_vroom_time_windows(jobs_tws_sql, &jobs_tws, &total_jobs_tws, - is_plain); - } - Vroom_time_window_t *shipments_tws = NULL; - size_t total_shipments_tws = 0; - if (shipments_tws_sql) { - get_vroom_shipments_time_windows(shipments_tws_sql, &shipments_tws, - &total_shipments_tws, is_plain); - } - - Vroom_vehicle_t *vehicles = NULL; - size_t total_vehicles = 0; - get_vroom_vehicles(vehicles_sql, &vehicles, &total_vehicles, is_plain); - - if (total_vehicles == 0) { - ereport(WARNING, (errmsg("Insufficient data found on Vehicles SQL query."), - errhint("%s", vehicles_sql))); - (*result_count) = 0; - (*result_tuples) = NULL; - pgr_SPI_finish(); - return; - } + Vroom_time_window_t *jobs_tws = NULL; + size_t total_jobs_tws = 0; + if (jobs_tws_sql) { + get_vroom_time_windows(jobs_tws_sql, &jobs_tws, &total_jobs_tws, + is_plain); + } - Vroom_break_t *breaks = NULL; - size_t total_breaks = 0; - if (breaks_sql) { - get_vroom_breaks(breaks_sql, &breaks, &total_breaks, is_plain); - } + Vroom_time_window_t *shipments_tws = NULL; + size_t total_shipments_tws = 0; + if (shipments_tws_sql) { + get_vroom_shipments_time_windows(shipments_tws_sql, &shipments_tws, + &total_shipments_tws, is_plain); + } - Vroom_time_window_t *breaks_tws = NULL; - size_t total_breaks_tws = 0; - if (breaks_tws_sql) { - get_vroom_time_windows(breaks_tws_sql, &breaks_tws, &total_breaks_tws, - is_plain); - } + Vroom_vehicle_t *vehicles = NULL; + size_t total_vehicles = 0; + get_vroom_vehicles(vehicles_sql, &vehicles, &total_vehicles, is_plain); + + if (total_vehicles == 0) { + ereport(WARNING, (errmsg("Insufficient data found on Vehicles SQL query."), + errhint("%s", vehicles_sql))); + (*result_count) = 0; + (*result_tuples) = NULL; + vrp_SPI_finish(); + return; + } - Vroom_matrix_t *matrix_rows = NULL; - size_t total_matrix_rows = 0; - get_vroom_matrix(matrix_sql, &matrix_rows, &total_matrix_rows, is_plain); + Vroom_break_t *breaks = NULL; + size_t total_breaks = 0; + if (breaks_sql) { + get_vroom_breaks(breaks_sql, &breaks, &total_breaks, is_plain); + } - if (total_matrix_rows == 0) { - ereport(WARNING, (errmsg("Insufficient data found on Matrix SQL query."), - errhint("%s", matrix_sql))); - (*result_count) = 0; - (*result_tuples) = NULL; - pgr_SPI_finish(); - return; - } + Vroom_time_window_t *breaks_tws = NULL; + size_t total_breaks_tws = 0; + if (breaks_tws_sql) { + get_vroom_time_windows(breaks_tws_sql, &breaks_tws, &total_breaks_tws, + is_plain); + } - clock_t start_t = clock(); - char *log_msg = NULL; - char *notice_msg = NULL; - char *err_msg = NULL; + Vroom_matrix_t *matrix_rows = NULL; + size_t total_matrix_rows = 0; + get_vroom_matrix(matrix_sql, &matrix_rows, &total_matrix_rows, is_plain); + + if (total_matrix_rows == 0) { + ereport(WARNING, (errmsg("Insufficient data found on Matrix SQL query."), + errhint("%s", matrix_sql))); + (*result_count) = 0; + (*result_tuples) = NULL; + vrp_SPI_finish(); + return; + } - int32_t loading_time = (int)((clock() - start_loading) / CLOCKS_PER_SEC) * 1000; + clock_t start_t = clock(); + char *log_msg = NULL; + char *notice_msg = NULL; + char *err_msg = NULL; - do_vrp_vroom( - jobs, total_jobs, - jobs_tws, total_jobs_tws, - shipments, total_shipments, - shipments_tws, total_shipments_tws, - vehicles, total_vehicles, - breaks, total_breaks, - breaks_tws, total_breaks_tws, - matrix_rows, total_matrix_rows, + int32_t loading_time = (int)((clock() - start_loading) / CLOCKS_PER_SEC) * 1000; - exploration_level, - timeout, - loading_time, + do_vrp_vroom( + jobs, total_jobs, + jobs_tws, total_jobs_tws, + shipments, total_shipments, + shipments_tws, total_shipments_tws, + vehicles, total_vehicles, + breaks, total_breaks, + breaks_tws, total_breaks_tws, + matrix_rows, total_matrix_rows, - result_tuples, - result_count, + exploration_level, + timeout, + loading_time, - &log_msg, - ¬ice_msg, - &err_msg); + result_tuples, + result_count, - time_msg("processing vrp_vroom", start_t, clock()); + &log_msg, + ¬ice_msg, + &err_msg); - if (err_msg && (*result_tuples)) { - pfree(*result_tuples); - (*result_tuples) = NULL; - (*result_count) = 0; - } + time_msg("processing vrp_vroom", start_t, clock()); - pgr_global_report(log_msg, notice_msg, err_msg); + if (err_msg && (*result_tuples)) { + pfree(*result_tuples); + (*result_tuples) = NULL; + (*result_count) = 0; + } - if (log_msg) pfree(log_msg); - if (notice_msg) pfree(notice_msg); - if (err_msg) pfree(err_msg); + vrp_global_report(&log_msg, ¬ice_msg, &err_msg); - if (jobs) pfree(jobs); - if (shipments) pfree(shipments); - if (vehicles) pfree(vehicles); - if (matrix_rows) pfree(matrix_rows); + if (jobs) pfree(jobs); + if (shipments) pfree(shipments); + if (vehicles) pfree(vehicles); + if (matrix_rows) pfree(matrix_rows); - pgr_SPI_finish(); + vrp_SPI_finish(); } @@ -256,35 +227,14 @@ PGDLLEXPORT Datum _vrp_vroom(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; TupleDesc tuple_desc; - /**********************************************************************/ Vroom_rt *result_tuples = NULL; size_t result_count = 0; - /**********************************************************************/ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - /*********************************************************************** - * - * _vrp_vroom( - * jobs_sql TEXT, - * jobs_time_windows_sql TEXT, - * shipments_sql TEXT, - * shipments_time_windows_sql TEXT, - * vehicles_sql TEXT, - * breaks_sql TEXT, - * breaks_time_windows_sql TEXT, - * matrix_sql TEXT, - * exploration_level INTEGER default 5, - * timeout INTEGER default -1, - * fn SMALLINT, - * is_plain BOOLEAN - * ); - * - **********************************************************************/ - char *args[8]; for (int i = 0; i < 8; i++) { if (PG_ARGISNULL(i)) { @@ -334,14 +284,7 @@ PGDLLEXPORT Datum _vrp_vroom(PG_FUNCTION_ARGS) { &result_tuples, &result_count); - /**********************************************************************/ - - -#if PGSQL_VERSION > 95 funcctx->max_calls = result_count; -#else - funcctx->max_calls = (uint32_t)result_count; -#endif funcctx->user_fctx = result_tuples; if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE) { @@ -426,8 +369,6 @@ PGDLLEXPORT Datum _vrp_vroom(PG_FUNCTION_ARGS) { values[14] = Int32GetDatum(result_tuples[call_cntr].departure_time); values[15] = PointerGetDatum(arrayType); - /**********************************************************************/ - tuple = heap_form_tuple(tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); diff --git a/src/vroom/vroom_driver.cpp b/src/vroom/vroom_driver.cpp index 61481662c..c9b40aa85 100644 --- a/src/vroom/vroom_driver.cpp +++ b/src/vroom/vroom_driver.cpp @@ -82,181 +82,185 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ void do_vrp_vroom( - Vroom_job_t *jobs, size_t total_jobs, - Vroom_time_window_t *jobs_tws, size_t total_jobs_tws, - Vroom_shipment_t *shipments, size_t total_shipments, - Vroom_time_window_t *shipments_tws, size_t total_shipments_tws, - Vroom_vehicle_t *vehicles, size_t total_vehicles, - Vroom_break_t *breaks, size_t total_breaks, - Vroom_time_window_t *breaks_tws, size_t total_breaks_tws, - Vroom_matrix_t *matrix_rows, size_t total_matrix_rows, - - int32_t exploration_level, - int32_t timeout, - int32_t loading_time, - - Vroom_rt **return_tuples, - size_t *return_count, - - char ** log_msg, - char ** notice_msg, - char ** err_msg) { - std::ostringstream log; - std::ostringstream err; - std::ostringstream notice; - try { - pgassert(!(*log_msg)); - pgassert(!(*notice_msg)); - pgassert(!(*err_msg)); - pgassert(!(*return_tuples)); - pgassert(!(*return_count)); - pgassert(jobs || shipments); - pgassert(vehicles); - pgassert(matrix_rows); - pgassert(total_jobs || total_shipments); - pgassert(total_vehicles); - pgassert(total_matrix_rows); - - auto start_time = std::chrono::high_resolution_clock::now(); - - Identifiers location_ids; - - for (size_t i = 0; i < total_jobs; ++i) { - location_ids += jobs[i].location_id; + Vroom_job_t *jobs, size_t total_jobs, + Vroom_time_window_t *jobs_tws, size_t total_jobs_tws, + Vroom_shipment_t *shipments, size_t total_shipments, + Vroom_time_window_t *shipments_tws, size_t total_shipments_tws, + Vroom_vehicle_t *vehicles, size_t total_vehicles, + Vroom_break_t *breaks, size_t total_breaks, + Vroom_time_window_t *breaks_tws, size_t total_breaks_tws, + Vroom_matrix_t *matrix_rows, size_t total_matrix_rows, + + int32_t exploration_level, + int32_t timeout, + int32_t loading_time, + + Vroom_rt **return_tuples, + size_t *return_count, + + char ** log_msg, + char ** notice_msg, + char ** err_msg) { + using vrprouting::alloc; + using vrprouting::to_pg_msg; + using vrprouting::free; + + std::ostringstream log; + std::ostringstream err; + std::ostringstream notice; + try { + pgassert(!(*log_msg)); + pgassert(!(*notice_msg)); + pgassert(!(*err_msg)); + pgassert(!(*return_tuples)); + pgassert(!(*return_count)); + pgassert(jobs || shipments); + pgassert(vehicles); + pgassert(matrix_rows); + pgassert(total_jobs || total_shipments); + pgassert(total_vehicles); + pgassert(total_matrix_rows); + + auto start_time = std::chrono::high_resolution_clock::now(); + + Identifiers location_ids; + + for (size_t i = 0; i < total_jobs; ++i) { + location_ids += jobs[i].location_id; + } + + for (size_t i = 0; i < total_shipments; ++i) { + location_ids += shipments[i].p_location_id; + location_ids += shipments[i].d_location_id; + } + + double min_speed_factor, max_speed_factor; + min_speed_factor = max_speed_factor = vehicles[0].speed_factor; + + for (size_t i = 0; i < total_vehicles; ++i) { + min_speed_factor = std::min(min_speed_factor, vehicles[i].speed_factor); + max_speed_factor = std::max(max_speed_factor, vehicles[i].speed_factor); + if (vehicles[i].start_id != -1) { + location_ids += vehicles[i].start_id; + } + if (vehicles[i].end_id != -1) { + location_ids += vehicles[i].end_id; + } + } + + /* + * Verify that max value of speed factor is not greater + * than 5 times the speed factor of any other vehicle. + */ + if (max_speed_factor > 5 * min_speed_factor) { + (*return_tuples) = NULL; + (*return_count) = 0; + err << "The speed_factor " << max_speed_factor << " is more than five times " + "the speed factor " << min_speed_factor; + *err_msg = to_pg_msg(err.str()); + return; + } + + /* + * Scale the vehicles speed factors according to the minimum speed factor + */ + for (size_t i = 0; i < total_vehicles; ++i) { + vehicles[i].speed_factor = std::round(vehicles[i].speed_factor / min_speed_factor); + } + + /* + * Create the matrix. Also, scale the time matrix according to min_speed_factor + */ + vrprouting::base::Base_Matrix matrix(matrix_rows, total_matrix_rows, + location_ids, min_speed_factor); + + /* + * Verify matrix cells preconditions + */ + if (!matrix.has_no_infinity()) { + (*return_tuples) = NULL; + (*return_count) = 0; + err << "An Infinity value was found on the Matrix. Might be missing information of a node"; + *err_msg = to_pg_msg(err.str()); + return; + } + + /* + * Verify size of matrix cell lies in the limit + */ + if (matrix.size() > (std::numeric_limits::max)()) { + (*return_tuples) = NULL; + (*return_count) = 0; + err << "The size of time matrix exceeds the limit"; + *err_msg = to_pg_msg(err.str()); + return; + } + + vrprouting::Vrp_vroom_problem problem; + problem.add_matrix(matrix); + problem.add_vehicles(vehicles, total_vehicles, + breaks, total_breaks, + breaks_tws, total_breaks_tws); + problem.add_jobs(jobs, total_jobs, + jobs_tws, total_jobs_tws); + problem.add_shipments(shipments, total_shipments, + shipments_tws, total_shipments_tws); + + auto end_time = std::chrono::high_resolution_clock::now(); + loading_time += static_cast( + std::chrono::duration_cast(end_time - start_time) + .count()); + + std::vector < Vroom_rt > results = problem.solve(exploration_level, timeout, loading_time); + + auto count = results.size(); + if (count == 0) { + (*return_tuples) = NULL; + (*return_count) = 0; + notice << "No results found"; + *notice_msg = notice.str().empty()? + *notice_msg : + to_pg_msg(notice.str().c_str()); + return; + } + + (*return_tuples) = alloc(count, (*return_tuples)); + for (size_t i = 0; i < count; i++) { + *((*return_tuples) + i) = results[i]; + } + + (*return_count) = count; + + pgassert(*err_msg == NULL); + *log_msg = log.str().empty()? + *log_msg : + to_pg_msg(log.str().c_str()); + *notice_msg = notice.str().empty()? + *notice_msg : + to_pg_msg(notice.str().c_str()); + } catch (AssertFailedException &except) { + (*return_tuples) = free(*return_tuples); + (*return_count) = 0; + err << except.what(); + *err_msg = to_pg_msg(err.str().c_str()); + *log_msg = to_pg_msg(log.str().c_str()); + } catch (const vroom::Exception &except) { + (*return_tuples) = free(*return_tuples); + (*return_count) = 0; + err << except.message; + *err_msg = to_pg_msg(err.str().c_str()); + *log_msg = to_pg_msg(log.str().c_str()); + } catch (std::exception &except) { + (*return_tuples) = free(*return_tuples); + (*return_count) = 0; + err << except.what(); + *err_msg = to_pg_msg(err.str().c_str()); + *log_msg = to_pg_msg(log.str().c_str()); + } catch(...) { + (*return_tuples) = free(*return_tuples); + (*return_count) = 0; + err << "Caught unknown exception!"; + *err_msg = to_pg_msg(err.str().c_str()); + *log_msg = to_pg_msg(log.str().c_str()); } - - for (size_t i = 0; i < total_shipments; ++i) { - location_ids += shipments[i].p_location_id; - location_ids += shipments[i].d_location_id; - } - - double min_speed_factor, max_speed_factor; - min_speed_factor = max_speed_factor = vehicles[0].speed_factor; - - for (size_t i = 0; i < total_vehicles; ++i) { - min_speed_factor = std::min(min_speed_factor, vehicles[i].speed_factor); - max_speed_factor = std::max(max_speed_factor, vehicles[i].speed_factor); - if (vehicles[i].start_id != -1) { - location_ids += vehicles[i].start_id; - } - if (vehicles[i].end_id != -1) { - location_ids += vehicles[i].end_id; - } - } - - /* - * Verify that max value of speed factor is not greater - * than 5 times the speed factor of any other vehicle. - */ - if (max_speed_factor > 5 * min_speed_factor) { - (*return_tuples) = NULL; - (*return_count) = 0; - err << "The speed_factor " << max_speed_factor << " is more than five times " - "the speed factor " << min_speed_factor; - *err_msg = pgr_msg(err.str()); - return; - } - - /* - * Scale the vehicles speed factors according to the minimum speed factor - */ - for (size_t i = 0; i < total_vehicles; ++i) { - vehicles[i].speed_factor = std::round(vehicles[i].speed_factor / min_speed_factor); - } - - /* - * Create the matrix. Also, scale the time matrix according to min_speed_factor - */ - vrprouting::base::Base_Matrix matrix(matrix_rows, total_matrix_rows, - location_ids, min_speed_factor); - - /* - * Verify matrix cells preconditions - */ - if (!matrix.has_no_infinity()) { - (*return_tuples) = NULL; - (*return_count) = 0; - err << "An Infinity value was found on the Matrix. Might be missing information of a node"; - *err_msg = pgr_msg(err.str()); - return; - } - - /* - * Verify size of matrix cell lies in the limit - */ - if (matrix.size() > (std::numeric_limits::max)()) { - (*return_tuples) = NULL; - (*return_count) = 0; - err << "The size of time matrix exceeds the limit"; - *err_msg = pgr_msg(err.str()); - return; - } - - vrprouting::Vrp_vroom_problem problem; - problem.add_matrix(matrix); - problem.add_vehicles(vehicles, total_vehicles, - breaks, total_breaks, - breaks_tws, total_breaks_tws); - problem.add_jobs(jobs, total_jobs, - jobs_tws, total_jobs_tws); - problem.add_shipments(shipments, total_shipments, - shipments_tws, total_shipments_tws); - - auto end_time = std::chrono::high_resolution_clock::now(); - loading_time += static_cast( - std::chrono::duration_cast(end_time - start_time) - .count()); - - std::vector < Vroom_rt > results = problem.solve(exploration_level, timeout, loading_time); - - auto count = results.size(); - if (count == 0) { - (*return_tuples) = NULL; - (*return_count) = 0; - notice << "No results found"; - *notice_msg = notice.str().empty()? - *notice_msg : - pgr_msg(notice.str().c_str()); - return; - } - - (*return_tuples) = pgr_alloc(count, (*return_tuples)); - for (size_t i = 0; i < count; i++) { - *((*return_tuples) + i) = results[i]; - } - - (*return_count) = count; - - pgassert(*err_msg == NULL); - *log_msg = log.str().empty()? - *log_msg : - pgr_msg(log.str().c_str()); - *notice_msg = notice.str().empty()? - *notice_msg : - pgr_msg(notice.str().c_str()); - } catch (AssertFailedException &except) { - (*return_tuples) = pgr_free(*return_tuples); - (*return_count) = 0; - err << except.what(); - *err_msg = pgr_msg(err.str().c_str()); - *log_msg = pgr_msg(log.str().c_str()); - } catch (const vroom::Exception &except) { - (*return_tuples) = pgr_free(*return_tuples); - (*return_count) = 0; - err << except.message; - *err_msg = pgr_msg(err.str().c_str()); - *log_msg = pgr_msg(log.str().c_str()); - } catch (std::exception &except) { - (*return_tuples) = pgr_free(*return_tuples); - (*return_count) = 0; - err << except.what(); - *err_msg = pgr_msg(err.str().c_str()); - *log_msg = pgr_msg(log.str().c_str()); - } catch(...) { - (*return_tuples) = pgr_free(*return_tuples); - (*return_count) = 0; - err << "Caught unknown exception!"; - *err_msg = pgr_msg(err.str().c_str()); - *log_msg = pgr_msg(log.str().c_str()); - } }