pax_global_header00006660000000000000000000000064136057416040014520gustar00rootroot0000000000000052 comment=ec3da91a74d34b992b737c769c2d48b04c9c16d4 libminizinc-2.4.2/000077500000000000000000000000001360574160400140345ustar00rootroot00000000000000libminizinc-2.4.2/.gitignore000066400000000000000000000006531360574160400160300ustar00rootroot00000000000000*.o *~ mzn2fzn solns2out makefile Makefile include/minizinc/parser.tab.hh lib/lexer.yy.cpp lib/parser.tab.cpp core build/ res/ vendor/ CMakeCache.txt CMakeFiles CMakeScripts cmake_install.cmake install_manifest.txt libminizinc.build libminizinc.xcodeproj CMakeLists.txt.user *.bak *.out *.err .vscode/c_cpp_properties.json .vscode/ipch tests/output tests/env tests/.pytest_cache __pycache__/ .mypy_cache/ .vscode/settings.json libminizinc-2.4.2/.gitlab-ci.yml000066400000000000000000000107571360574160400165020ustar00rootroot00000000000000stages: - build - test - trigger .download_script: &download_script - curl --location --header "PRIVATE-TOKEN:$ACCESS_TOKEN" --silent https://gitlab.com/api/v4/snippets/1796163/raw | tr -d '\r' > download.sh variables: # Vendor solver locations Gecode_ROOT: "$CI_PROJECT_DIR/vendor/gecode" Gurobi_ROOT: "$CI_PROJECT_DIR/vendor/gurobi" CPlex_ROOT: "$CI_PROJECT_DIR/vendor/CPLEX_Studio/cplex" OsiCBC_ROOT: "$CI_PROJECT_DIR/vendor/cbc" # CCache settings CCACHE_DIR: "$CI_PROJECT_DIR/.ccache" CCACHE_MAXSIZE: "100M" .build_template: &build_definition stage: build before_script: *download_script script: - sh download.sh vendor master vendor:${MZNARCH} vendor.zip - unzip -q vendor.zip - mkdir -p build - cd build - cmake -G"$CMAKE_ARCH" -DCMAKE_BUILD_TYPE=Release -v .. -DBUILD_REF=$CI_PIPELINE_ID -DUSE_PROPRIETARY=OFF -DCMAKE_INSTALL_PREFIX="$CI_PROJECT_DIR/minizinc" - cmake --build . --config Release - cmake --build . --config Release --target install artifacts: paths: [minizinc/] cache: key: "$CI_JOB_NAME" paths: [.ccache, vendor.zip*] # TODO: Uncomment when builds are required on merge request # only: [refs, branches, tags, merge_requests] build:linux: <<: *build_definition image: dekker1/minibuild:cpp variables: MZNARCH: "linux" CMAKE_ARCH: "Ninja" tags: [linux, docker] build:musl: <<: *build_definition image: dekker1/minibuild:alpine variables: MZNARCH: "musl" CMAKE_ARCH: "Ninja" tags: [linux, docker] build:osx: <<: *build_definition stage: build variables: MZNARCH: "osx" CMAKE_ARCH: "Ninja" tags: [osx, cmake, cpp] build:win64: stage: build variables: MZNARCH: "win64" CMAKE_ARCH: "Visual Studio 15 2017 Win64" before_script: - curl -o download.sh --location --header "PRIVATE-TOKEN:%ACCESS_TOKEN%" --silent https://gitlab.com/api/v4/snippets/1796163/raw - dos2unix download.sh script: - sh download.sh vendor master vendor:%MZNARCH% vendor.zip - unzip -q vendor.zip - if not exist "build" mkdir build - cd build - cmake -G"%CMAKE_ARCH%" .. -DBUILD_REF=%CI_PIPELINE_ID% -DUSE_PROPRIETARY=OFF -DCMAKE_INSTALL_PREFIX="%CI_PROJECT_DIR%/minizinc" - cmake --build . --config Release - cmake --build . --config Release --target install artifacts: paths: [minizinc/] cache: key: "win64" paths: [vendor.zip*] tags: [win64, cmake, cpp] # TODO: Uncomment when builds are required on merge request # only: [refs, branches, tags, merge_requests] build:wasm_complete: image: trzeci/emscripten stage: build variables: MZNARCH: "wasm" CMAKE_ARCH: "Unix Makefiles" tags: [docker] before_script: *download_script script: - sh download.sh vendor master vendor:wasm vendor.zip - unzip -q vendor.zip - mkdir -p build - cd build - emconfigure cmake -G"$CMAKE_ARCH" -DCMAKE_FIND_ROOT_PATH="/" -DGECODE_ROOT="$GECODE_ROOT" -DOSICBC_ROOT="$OSICBC_ROOT" -DCMAKE_BUILD_TYPE=MinSizeRel -DEMSCRIPTEN_GENERATE_BITCODE_STATIC_LIBRARIES=1 -v .. -DBUILD_REF=$CI_PIPELINE_ID -DUSE_PROPRIETARY=OFF -DCMAKE_INSTALL_PREFIX="$CI_PROJECT_DIR/minizinc" - cmake --build . --config MinSizeRel - cmake --build . --config MinSizeRel --target install artifacts: paths: [minizinc/] cache: key: "$CI_JOB_NAME" paths: [.ccache, vendor.zip*] when: manual build:wasm_minimal: image: trzeci/emscripten stage: build variables: MZNARCH: "wasm" CMAKE_ARCH: "Unix Makefiles" tags: [docker] before_script: *download_script script: - sh download.sh vendor master vendor:wasm vendor.zip - unzip -q vendor.zip - mkdir -p build - cd build - emconfigure cmake -G"$CMAKE_ARCH" -DCMAKE_BUILD_TYPE=MinSizeRel -DEMSCRIPTEN_GENERATE_BITCODE_STATIC_LIBRARIES=1 -v .. -DBUILD_REF=$CI_PIPELINE_ID -DUSE_PROPRIETARY=OFF -DCMAKE_INSTALL_PREFIX="$CI_PROJECT_DIR/minizinc" - cmake --build . --config MinSizeRel - cmake --build . --config MinSizeRel --target install artifacts: paths: [minizinc/] cache: key: "$CI_JOB_NAME" paths: [.ccache, vendor.zip*] when: manual # ----------- Test Suite ----------- include: - local: '/tests/.gitlab-ci-testing-pipeline.yml' # ----------- Trigger FindMUS pipeline ----------- trigger:findmus: stage: trigger image: dekker1/minibuild:package script: - "curl --request POST --form token=$TRIGGER --form ref=master https://gitlab.com/api/v4/projects/minizinc%2FFindMUS/trigger/pipeline" dependencies: [] tags: [linux, docker] only: [develop] libminizinc-2.4.2/CHANGES.txt000066400000000000000000001463721360574160400156620ustar00rootroot00000000000000====================== # MiniZinc Changelog # ====================== All bug numbers refer to the issue tracker at https://github.com/MiniZinc/libminizinc/issues Version 2.4.2 ============= Changes: - The test suite is now integrated into the continuous integration system. Bug fixes: - Fix flattening of negated disjunctions (#359). - Fix simplification of Boolean constraints (repeated simplification could sometimes crash). - Fix memory management during flattening of conditionals (#358). - Fix type inference for rewriting of sums into count constraints, and only apply the rewriting for var type-insts. - Fix handling of solution checkers (these used to produce spurious error messages). Version 2.4.1 ============= Changes: - Improve compiler optimisation for some linear, multiplication and Boolean constraints. - Improved translation of lex and all_equal constraints when the arrays have no or only one variable. Bug fixes: - Fixed regular expression constraint for expressions containing negated character classes (^ operator). - Fix element constraint in nosets.mzn library when set domains are not contiguous. - Correctly identify Windows paths starting with // or \\ as absolute (this enables the parser to open files stored on network drives). - Use set_in constraints (rather than int_in) for internal Gecode-based presolver. This fixes some issues when compiling with -O3. - The optimisation phase of the compiler now fully substitutes par bool variables (these can be introduced into the FlatZinc during multipass compilation). Partially fixes #357. - Fixed the reference counting for variables that are re-used in multipass compilation. Partially fixes #357. - Remove incorrect error handling when parsing from strings rather than files. Partially fixes #357. - Made the is_fixed builtin work for more types. Fixes #356. - Enable rewriting of sum(i in x)(i=c) op d and count(x,y) op z into global counting constraints. - Split up count global constraints into separate files for reified versions. - Use contiguous range for array index set in set_lt for nosets.mzn. - Negate results of conditionals if required. Fixes #355. - Partiality of conditional needs to be translated in root context (even if conditional itself is negated). Fixes #355. - Don't copy function into output again if it was already copied (and made par) before. Fixes #323. - Define card function on var sets in terms of set_card FlatZinc builtin. - Don't set bounds for set variables in internal Gecode presolver. Version 2.4.0 ============= Changes: - The compiler now detects counting constraints in expressions such as count(i in x)(i=3) <= 4 and rewrites them into global counting constraints. This is now the preferred way to specify counting. The atmost/atleast/exactly constraints on integer variables have been deprecated, and versions of count predicates with par variables have been added. FlatZinc solvers that supported atmost/atleast/exactly should now support the corresponding fzn_count_?_par predicates. - The compiler now supports the command line option --output-detailed-timing, which provides timing information for each toplevel constraint item, or for each line of code when used in conjunction with the --keep-paths option. - The library now contains annotations for deprecated library functions. - A par version of the inverse function has been added (include inverse_fn.mzn to use it). - The common case of sums of optional variables is now handled more efficiently. This case often arises from generator expressions with variable where clauses. - Added set_to_ranges built-ins to enable efficient iteration over sets. These are used to implement set_in for float variables, which was missing before. - The Gurobi and CPLEX backends now support the --random-seed command line option. - The Gurobi and CPLEX backends now use nodefile for search trees exceeding 500 MB (--nodefilestart can change this value and --nodefiledir the folder.) - The MIPDomains optimisations have been switched back on by default. The optimisations have also been strengthened for some special cases. - Without the MIPdomains postprocessing, linearisation of variable domains with holes now uses set_in instead of individual not-equal constraints, which may result in more compact FlatZinc. - Linearisation of multiplication can now consider the exact domain of a factor. - The product functions have been made non-recursive in order to support longer arrays. - Bounds inference for results of if-then-else expressions has been improved. - Support for optional float variables has been added. - The interfaces to CBC, CPLEX and Gurobi now report correctly that they support verbose output during solving (so that the "verbose solving" option is available from the MiniZinc IDE). Bug fixes: - Fixed output handling on Windows (output is now processed on the main thread, so that exceptions thrown during output are printed correctly, and memory management is thread safe). - Fixed decomposition of reified mdd constraint, and strengthened decompositions of mdd and cost_mdd. - Fix handling of variable re-definitions (e.g. converting sets to arrays of bools), which would previously sometimes result in variables being removed although they were required for output, or the reverse mapping function not being available in the output model. - Include regular.mzn from regular_regexp.mzn. (#351) - Inlining of function calls has been moved from the flattener into the type checker, and it now is more strict about which functions can be inlined in order to avoid overloading issues. - Updated fzn_count_{neq,leq,lt,geq,gt}, fzn_global_cardinality_low_up{,_reif} to use use the count_eq predicate. (#334, #335) - Fixed the documentation for several constraints, which did not display as bullet point lists as intended. - Copy function/predicate declarations into FlatZinc without annotations, since most FlatZinc parsers would not expect annotations and fail to parse. - Process right hand side of par VarDecls to make sure any identifiers it uses are copied into the output model. Fixes #336. - Fix type checking for conditionals where the else branch has enum type but the then branch has int type. - Make the deopt function return correct enum instead of int type. - Fix for path handling when 'needRangeDomains' is active. Avoids infinite recursion in the compiler. - Fix race condition in temporary file generator for Windows. (#349) - Register fzn_ names for Gecode presolver. Fixes command line flags -O3 and above. - Fix par evaluation of float and bool set comprehensions. - Fix documentation of array_bool_xor. Fixes minizinc/minizinc-doc#13. - Fix the round() built-in to correctly round negative numbers - Fix computation of intersection of domains when assigning an array to an array variable. Fixes #310. - Add defines_var annotations for functional global constraints. Fixes #345. - Add set_lt_reif/set_le_reif to flatzinc builtins library. Fixes #338. - Clarify set order based on spec. Fixes #339. - Don't return already removed VarDecl objects from CSE. Fixes #346. - Do not post y!=0 constraint if 0 is not in the domain (workaround for a limitation in the handling of basic float constraints). Fixes #344. - Help type checker by making deopt/occurs argument types explicit. Fixes #331. - Fix transfer of domains when aliasing one variable to another - MIP: fix for aux_float_ne_if_1 - MIP: int_(eq/ne)_imp: don't force eq_encode without MIPdomains - Fix a typo in the definition of fzn_at_least_int{,_reif} - Fix dependency problem in the gecode_presolver table specification - Add seq_precede_chain.mzn to globals.mzn. Fixes #332. - Don't assign right hand side of set variables if domain is singleton. Fixes #330. - Don't invalidate float bound just because an expression contains an integer. - Fix copying of let expressions. - Put lexer and parser helper functions into MiniZinc namespace to avoid linker issues. Fixes #325. - Reset array index sets defined in lets inside recursive function calls. - Arrays copied into output model need to have par type-inst. Fixes #322. - Don't complain when same function is registered twice. Fixes #323. - Fix partiality handling of if-then-else expressions. - Track whether variable is used in an output array before making decision to compress implication chains. Fixes #318. Version 2.3.2 ============= Changes: - Add warm starts and subtour cuts to CBC interface. - Add documentation and assertion requiring that mdds are deterministic, and add nondeterministic variant of mdd constraint. - Add -s to the standard flags supported by MIP interfaces. - Add flag --output-output-item to include user specified output item in the formatted JSON and DZN output. Bug fixes: - Fix a bug that could leave unused variables in the resulting FlatZinc. - bounded_dpath should rewrite to fzn_bounded_dpath. Fixes #300. - Fix definition of sum_set. - Check if overloaded function required for output. Fixes #303. - Move regular constraint with set argument to its own file. - Flatten assignment generators if necessary. - Simplify fzn_value_precede_chain_int and avoid use of element predicate. Fixes #307. - Only initialise par opt variables as absent if they are not arrays. - Fix the description of the neural_net predicate. - Fix regular constraint with regular expressions (stopped working in 2.3.0). - Fix the model interface output to include the same variables as the generated output statement. - Fix CSE for removed variable declarations. Could lead to reified constraints not being compiled correctly when the control variable got fixed to true. Version 2.3.1 ============= Bug fixes: - Report error when trying to assign an array literal to an array variable with incompatible index set. - Fix partial evaluation of expressions, so that only par expressions are fully evaluated. Fixes #298. - Remove carriage returns when reading piped solver output on Windows. - Canonicalize paths of executables to avoid spurious warnings about multiple executables for the same solver. - Add implementations for != on arrays. - Compute quotient bounds before decomposition of int_div in linearisation library. - Propagate domain constraints on variables that are aliased (previously domain constraints could get lost). - Propagate domain constraints from left-hand-side to right-hand-side in variable assignments. - piecewise-linear: reuse decomposition for X when only Y-values change. - nosets: add set_in_imp(var set) and simplify set_in_reif, set_eq(var set, var set). - linearisation: improved compilation of set_in constraints. Version 2.3 =========== Major Changes: - The compiler can now generate FlatZinc with half reified constraints. See https://www.minizinc.org/doc-2.3.0/en/fzn-spec.html#reified-and-half-reified-predicates for more details. - The standard library of global constraints has been reorganised, making it easier for solvers to override just the bits that they support. See https://www.minizinc.org/doc-2.3.0/en/fzn-spec.html#solver-specific-libraries for more details. - There is experimental support for solvers that can read AMPL NL files. Minor Changes: - The JSON input and output has been improved, with full support for enums and optional types. - A new compiler option -g has been added, which turns variable domain changes into constraints (useful for debugging models). - The SCIP interface has been updated, with support for indicator constraints, bounds disjunctions and a native cumulative constraint. - Error reporting has been improved, with location information available for errors in par float expressions as well as include items. - The timeout command line parameter now also applies to compilation itself (#281). - Operations on par float values are now checked for overflows. - The arg_min/arg_max constraints have been improved, with new special versions for Boolean variables, and a better standard decomposition. - if-then-else-endif expressions with variable conditions are now compiled to a predicate call (rather than handled by the compiler), which enables solver libraries to implement these as native constraints or special decompositions. - Dividing a variable by a constant is now translated as a multiplication (to keep the constraints linear). - A new piecewise_linear predicate has been added to the library to make it easier to specify piecewise linear constraints. - Print number of solutions as mzn-stat after solving (#244). - Make search annotations work for arbitrary array index sets. Bug fixes: - Translate let expressions that contain constraints or variables as var type-inst. Fixes #263. - Fix JSON array parsing by counting elements instead of commas. - Fix parsing of the -p flag (#271). - Fix type checking for array declarations with single enum type inst identifier. E.g. array[$$T] of $U previously matched any multi-dimensional array, and now only matches one-dimensional arrays with any enum index set. - Fix computation of function return type when using type inst variables (#272). - Evaluate each variable declaration only once in a par let expression. - Check domain constraints on variable declarations in par let expressions. - Try .exe/.bat on windows when using (constructed) absolute paths. - Fix array slicing to support empty slices (#275). - Fix a bug in the parser that could cause crashes on certain syntax errors. - Fix the type of bool2int for arrays. - Initialise counter for introduced variable ids based on names in original model. This avoids reusing variable names if the user model contains names such as X_INTRODUCED_0_. - Fix compilation of nested clause/exist constraints, and improve handling of negation. Tries to use primitive negation instead of creating negated constraints. Should help with half-reification by creating more positive contexts. - Reorder fields in basic data structures to reduce padding on 64 bit platforms (improved memory footprint). - Perform type coercion after desugaring array slicing. - Translate arguments to bool2int, exists, forall in positive context even if those functions are redefined. - Don't evaluate par array literals twice (inefficient, and can lead to incorrect results when using random number generators). - Terminate child processes when minizinc process is terminated by signal. - Fix function return value array index check for empty arrays (#286). - Fix translation of constant false where clause in array comprehension. - Report error when json multi-dimensional array is not rectangular. - Check index sets of function arguments (#273). - Ignore partiality variables from CSE table when compiling _reif and _imp predicates (#269). - Flatten comprehensions with variable generators or where conditions before evaluating any par functions on them (#259). - Add missing redefinitions of basic operators and search annotations for optional integers. - Resolve filenames given on the command line relative to working directory, and warn if file in working directory has same name as included file from the library. Fixes #276. - Update nosets library with a valid redefinition of set_less over booleans. - Fix translation of showJSON (#294). - Only apply set2array coercion for supported types, otherwise report error (#295). - Improve special case reasoning for abs on strictly negative variables. - Add bounds for floating point min/max result in the standard library. Version 2.2.3 ============= Bug fixes: - Fix some typos in the library documentation. - Fix solution checking. - Fix line numbers in parsed locations on 64 bit platforms. Fixes #255. - Fix bounds computation for calls. Partially fixes #255. - Fix translation of var where clauses with more than 3 par components. Fixes #253. Version 2.2.2 ============= Changes: - Some changes to the optimisation phase of the compiler, to take into account more variables and constraints. - Preliminary support for MIP cuts based on graph algorithms (only available when compiled with boost C++ libraries; not part of the binary distribution). - Set Release as default build type when nothing is specified (for CMake platforms that do not support multiple build types, like Makefiles). - Add builtins outputJSON() and outputJSONParameters() for creating an array of strings that capture the output and parameters of the model as JSON. - On Linux and macOS, add /usr/share/minizinc/solvers and /usr/local/share/minizinc/solvers to list of paths where solver configuration files can be placed. - Add OSICBC_INCLUDEDIR and OSICBC_LIBDIR cmake flags. Fixes #247. - Output search paths for solver configurations using --solvers command line option. - Add support for Gurobi 8.1 - Support parsing from stdin and files at the same time. Fixes #242. Bug fixes: - Fix crash when flattening top-level array comprehensions with var where clauses. Fixes #250. - Support input files with more than 1M lines. Fixes #245. - Special case handling for array literals in top-level foralls: flatten in root context. - Fix translation of if-then-else for branches with undefined right hand sides. - Only propagate defines_var annotation to the variable that's actually being defined (not others that arise from the same decomposition). - Don't flatten arguments of predicates like symmetry_breaking_constraint. - Remove output_var and output_array annotations from user models (these could cause crashes). - Fix precedences for weak operators (~+, ~-, ~=, ~*). - Fix min and max for opt var arrays to work when the bounds of the arrays are unknown. - Fix a bug in bounds computations for function calls. - Add missing superset FlatZinc builtin. - Fix includes in file values.hh for some platforms. - Fix a garbage collection issue when printing solutions. - Deal with the case that a variable that's required for output is assigned to a par variable. - Throw type error when an array has only absent values. Fixes #239. - Flatten all arrays in FlatZinc, also those coming from functional definitions. Fixes #240. - Use list of strings as mzn_solver_path entry in the preferences json file. Fixes #241. - Fix crash when output variable is defined using recursive function Version 2.2.1 ============= Changes: - all_different, all_equal, {int,set,float,bool}_search now accept multi-dimensional arrays. - Add exponentiation operator (^). - Improve layout of generated library documentation for some constraints. - Relax typechecking to allow assignment of empty array ([]) to multi-dimensional array variables. This is required to make empty arrays work in JSON data files. - Enumerated types can now be initialised using lists of strings. This enables enumerated type support in JSON. Bug fixes: - Cumulative constraint for linear solvers now accepts empty arrays. - show2d/show3d functions now do not add quotes around array elements and work for empty arrays. - Add support for slicing of arrays with enumerated types. Fixes #229. - Fix slicing of 1d arrays. - Fix bounds computation for float variable declarations. Fixes #225. - When FlatZinc solver is terminated due to a timeout, do not report this as an error. - Fix pretty-printing of multi-dimensional arrays where dimensions other than the first one are empty. Fixes #236. - Add support for where clauses on generator assignment expressions. Fixes #237. Version 2.2.0 ============= This is a major release of MiniZinc, introducing many new features and improvements. Major new features: - New minizinc command line tool Previous releases contained a minizinc command line tool that was not much more than a simple script that could execute the compiler, solver and output processor. The minizinc executable in version 2.2.0 is now the main frontend to compilation and solving and integrates all of the functionality. It has access to all installed MiniZinc solvers (both internal solvers and those interfaced through FlatZinc files), and can automatically select the required options (e.g., to include the solver-specific MiniZinc globals library). You can get a list of available solvers using the --solvers command line option, and select a solver using --solver. The minizinc executable can now also be used as a replacement for mzn2fzn (using -c) and solns2out (using --ozn-file). - Multi-pass compilation The compiler can now perform multiple passes in order to improve the target FlatZinc code. This can be controlled using the -O command line flags (-O0 to -O4). Multi-pass compilation is particularly useful when the target solver requires sophisticated decomposition of global constraints (such as for MIP solvers). - Solution checking You can now supply an additional model that will be used to check each solution produced by your main model. This can be useful for teaching MiniZinc (to give students automatic feedback) and if your main model is very complex but checking that a solution is correct is easy. - MIP solvers: support for FICO Xpress, and loading IBM ILOG CPLEX as a plugin We have added support for FICO Xpress (this requires compiling MiniZinc from sources). CPLEX can now be loaded as a plugin, which means that the binary distribution of MiniZinc has built-in CPLEX support (just bring your own CPLEX dll). - Language extensions The MiniZinc language has been extended with two new features. * Array slicing introduces syntax to conveniently select rows, columns or entire slices of arrays. For example, x[3,..] selects the third row of array x, while x[..,4] selects the fourth column, and x[3..5,2..7] selects a slice of rows 3 to 5 and columns 2 to 7. * Generator expressions can now contain multiple where clauses, e.g. forall (i in S where foo(i), j in T where i then endif" (where is bool) - Decomposition of one variable type to another (e.g. set into array of bool) has been improved. - MIP solvers Gurobi and IBM ILOG CPLEX use node files when over 3GB working memory - Gurobi and CPLEX support the MIPfocus parameter - Gurobi supports MiniZinc search annotations by setting fixed branching priorities Bug fixes: - Consult the bug tracker at https://github.com/MiniZinc/libminizinc/issues Version 2.1.7 ============= Changes: - Improved linearisation for some element constraints. - Improve performance of optimisation phase by using a queue instead of a stack. - Add --dll option for Gurobi backend to specify the Gurobi DLL to load. - Add more defines_var annotations. Bug fixes: - Fix generation of variable names in output model (sometimes could contain duplicates). - Fix enum type inference for array literals with empty sets as their first arguments. Fixes #180. - Fix incorrect simplification of float domain constraints. Fixes #159. - Fix ceil builtin for float values. - Add superset decomposition for solvers that do not support set variables. - Fix three bugs in the garbage collector. - Fix a bug in flattening that would create duplicate variables when a variable declaration referred to another one in its type-inst. - Fix a crash in flattening of partial functions. Fixes #187. - Add missing deopt builtins for all par types. - Fix output for arrays of sets of enums. - Define more functions on par opt types. Fixes #188. - Fix type checker to accept arrays of opt set values. - Support printing of opt enum types. Fixes #189. - Fix evaluation of comprehensions in recursive functions. - Fix output of Gurobi backend when used in conjunction with solns2out. - Fix pthread linking for mzn-cbc. - Catch type error when set literal is declared that contains another set. Version 2.1.6 ============= Bug fixes: - Fully evaluate parameters before binding formal arguments when evaluating call expressions. Fixes #177. - Fix incorrect simplification of Boolean constraints assigned to variables that are assigned to false - Fix bug in flattening of linear equations that contain the same variable on both sides - Fix un-trailing for let expressions, which could sometimes cause incorrect code to be emitted when lets are evaluated in nested loops. Fixes #166. - Fix bug in JSON output of one-dimensional array literals - Fix unification of enum type-inst variables Version 2.1.5 ============= Changes: - Some improvements to the linearisation library. - Make parser read multiple .mzn files correctly. - Enable better bounds computation for array access expressions on fixed arrays. - Perform better constant folding during optimisation phase. Fixes #155. - Don't rewrite pow function into multiplication in the case of power of 2. - Save some memory by making certain internal data structures more compact. - Improve source code location of identifiers in generator calls (should give more precise error messages). - Produce an error message when a comprehension attempts to iterate over an infinite set. - Produce better error messages for operations on infinite values (previously some errors did not contain a source code location). - Speed up garbage collection by pre-allocating some memory. Bug fixes: - Fix range check for float literals in arrays. - Fix a bug where a constraint could be removed incorrectly. Fixes #150. - Include variables for dzn and json output from all included models, not just the main model. Fixes #153. - Produce multi-dimensional arrays in json output. Fixes #156 and #157. - Remove incorrect closing bracket from json output. Fixes #154. - Fix bounds computation of par int and float arrays. - Don't allow var access to arrays of strings or annotations (since that would require an element constraint and var string / var ann types). - Introduce int2float constraints where necessary for some linearisations. Version 2.1.4 ============= Changes: - Add warning for MIP solvers that do not support -a option for satisfaction problems. - Print introduced variable names with additional underscore to make debugging FlatZinc easier. Fixes #147. - Add support for pow function in linearisation library. - Add support for parallel solving with CBC. - Flatten top-level conjunctions in the order defined in the model. Bug fixes: - Fix a garbage collection bug that could cause dangling pointers when expressions were copied. - Fix type checker to allow empty arrays to be assigned to variables declared as arrays of enums. - Fix infeasibility check in MIP translation for some inequality constraints. - Improved defines_var annotations for reified xor constraints. Fixes #146. - Fix output of empty integer sets and deal with empty arrays in output models. - Fix MIP translation when boolean variables were removed due to aliasing. - Improve corner cases for linearisation of cumulative constraint. - Properly report undefinedness in par bool expressions. - Enable some additional constant folding during flattening. Fixes #149. Version 2.1.3 ============= Changes: - Remove more internal annotations from the generated FlatZinc. - Detect failure earlier if optimisation pass leads to fixing of variables outside their domains. Bug fixes: - Fix CBC backend to correctly print UNSAT message for models where the compiler already detected unsatisfiability, and print solution separators even where there is no other output. - Add missing var_dom function for arrays of optional integer variables. Fixes #133. - Fix aliasing for optional integer variables. Fixes #132. - Remove all annotations from output model. - Fix computation of return type for functions that return arrays of enums. - Don't output newline if user-defined solution separator or status message is empty - Fix return type computation for functions where return type contains enums. - Check finiteness of float literals and bounds. Fixes #138. - More checks for function return values. Fixes #136. - Fix var int comprehensions (now triggers error message instead of crash for var set of int comprehensions). Fixes #135. - Fix output of variables with quoted identifiers. - Fix flattening of let expressions that contain variables with undefined (i.e., partial) right hand side. - Make printing of error messages to stdout or stderr more consistent across executables. - Fix type checking of initialisation of enum types. - Improve error messages for array access and index set errors. Fixes #131. - Fix definition of multi-dimensional element constraints to impose correct bounds on index variables. - Fix binding analysis during type checking, which did not handle the shadowing of top-level declarations by comprehension generators correctly. Fixes #129. Version 2.1.2 ============= Bug fixes: - Fix a bug in the type checking for generators that iterate over arrays of enums. - Fix a bug in the output handling of arrays of enums. - Fix handling of multiple output items (only the last item was compiled, now the concatenation is used for output as defined in the specification). Version 2.1.1 ============= Changes: - Add missing min/max functions for set variables. Can be redefined to solver builtins using the new redefinitions-2.1.1.mzn library file. - Add support for option type expressions as objective functions. - Automatically coerce arrays constructed using ++ to any enum index set (in addition to array literals and comprehensions). Bug fixes: - Include cmath header to fix compilation issues with some compilers. Fixes #125. - Fix a garbage collection bug in the type checking for enumerated types that would sometimes lead to crashes or incorrect error messages. - Fix type checking of comprehensions that involve enumerated types. - Fix bounds computation for var sets of enumerated types. - Support anon_enum function as documented. Version 2.1.0 ============= Changes: - MiniZinc now supports enumerated types. - Solvers can be interfaced directly to the MiniZinc library, and MiniZinc comes with direct support for the CBC, Gurobi and CPLEX MIP solvers. - The linearisation library has been updated, resulting in much better FlatZinc being generated for MIP solvers. - Data files can be in JSON format, and MiniZinc can produce JSON output (using the --output-mode command line option). - Variables can be annotated as ::add_to_output instead of writing an output item. - The compiler can output information about the parameters and output variables of a model (using the --model-interface-only option). - Floats are handled better (detecting infinities and handling sets of floats). - Bounds can be computed for more expressions (instead of failing with an error message). Bug fixes: - Fix a bug in optimization that could remove variables even if they are used. Fixes #123. - Fix float variable declarations with sets of floats as domains. Fixes #117 and #98. - Fix type checking and evaluation of asserts with array arguments. Fixes #109. - Fix abs(var float) declaration to work on floats without declared bounds. Fixes #106. - Fix a bug in the computation of int and float bounds that could result in incorrect bounds in some cases. Fixes #94. - Fix garbage collection when creating output models. Fixes #77. - Fix binary operators on optional variables (in some cases comparison operators were reversed). - Fix optimization of unconstrained variables (could sometimes lead to constraints being removed although they were not subsumed). Version 2.0.14 ============== Changes: - Less aggressive aggregation of linear expressions in cases where it leads to much less efficient FlatZinc. - Don't create temporary variable for an array literal if it is discarded immediately anyway. - Only create new partiality variable for if-then-else expression if there's at least one var condition. - Replace recursive definitions of array_intersect and array_union with iterative ones. Bug fixes: - Don't report warnings about partiality when using extended generator expressions. - Include cmath to enable building with some versions of gcc. - Constrain result of function call based on function return type if necessary. - Make sure linear expressions generated during binding of variables are properly flattened (including simplification of the linear expression) Version 2.0.13 ============== Bug fixes: - Fix a bug in the Common Subexpression Elimination table of the compiler, which could lead to some constraints being dropped (especially when using linear redefinitions). - The output model sometimes did not include all required definitions, in particular when array declarations used identifiers to specify the dimensions. - The generated FlatZinc sometimes still contained bool variables that were not connected to the rest of the model, which could produce incorrect solutions being printed. - Fix a bug where warnings (e.g. about partial functions) could lead to crashes. - Fix the bounds computation for integer and float variables, which could produce incorrect bounds for linear expressions. Fixes #94. Version 2.0.12 ============== Changes: - Partial functions are now always evaluated in their Boolean context, independent of whether they are par or var. If the result of a partial function is statically known to be undefined (such as division by zero or array access out of bounds), and it is used in a constraint expression, this now results in a warning instead of an error. Warnings can be turned off using the ::maybe_partial annotation. Fixes #43 and #74. Bug fixes: - Fix a bug in the optimisation phase related to unification of aliased variables. - Fix short-circuit evaluation of Boolean expressions. - Fix a bug in the optimisation phase related to repeated simplification of some Boolean expressions. - Handle errors in output produced by solver without solns2out crashing. Fixes #80. - Fix a bug in the integer bounds computation that caused bool2int with an embedded conditional to crash. - Fix a problem with short-circuit compilation of == expressions when one side was a var opt bool. - Stop compilation when model is failed. Fixes a bug where mzn2fzn would sometimes not clean up the FlatZinc enough for the solver. Version 2.0.11 ============== Bug fixes: - Fix parsing of hex and octal literals. Fixes #71. - Fix compilation of extended comprehensions. Fixes #72. - Fix computation of float array access bounds. - Fix aggregation of clauses (could sometimes ignore the negative literals). Version 2.0.10 ============== Bug fixes: - Fix a bug in the optimiser that could lead to undefined variables in the generated FlatZinc. Fixes #70. Version 2.0.9 ============= Bug fixes: - Need to take return type into account when copying functions to output model. Fixes #55. - Evaluate calls that result in arrays using eval_arraylit. Fixes #57. - Move inverse function to its own library file, so that it remains available when a solver provides an alternative for the inverse predicate. - Optimisation phase now recursively checks constraints when elements in an array become fixed. - Fix CMakeLists file to work for paths that contain spaces. - Distinguish between infix operators and regular functions in the generated html documentation. Fixes #61. - Made parser more robust against incorrect code. - Fix increment/decrement operators for IntVals and make all operations throw correct overflow exceptions. - Fix automatic type coercion for variables declared in let expressions. - Fix a crash when printing some error messages. - Fix compute_div_bounds builtin to return correct result for a division by zero. - Fix optimisation of Boolean constraints to use pointer equality instead of structural equality (same expression can occur multiple times in the FlatZinc). - Only optimise constraints that have not been removed yet. - Fix declaration of functional version of bin_packing_load. Fixes #64. - Set type of arrays returned from polymorphic functions. Fixes #65. - Fix parsing of quoted unary operator calls. - Only compute set functions when bounds are valid. Fixes #66. - Compute proper bounds for if-then-else expressions. - Report error when no reified version of a constraint is available. Fixes #67. - Fix type checking of annotations on binary operators. - Keep annotations when rewriting linear constraints and remove is_defined_var annotations from fixed variables. Fixes #69. Changes: - Integer, Boolean and float literals are now cached to achieve better memory performance for some models. - Improve performance of parsing integer literals. - Improve handling of clause constraints. - Add source files of MiniZinc specification to the repository. - Limit maximum array size to enable better error messages. - Add implied_constraint predicate as a synonym for redundant_constraint. Version 2.0.8 ============= Bug fixes: - Fix incorrect negation of some reified comparisons. - Make lb/ub functions work in more cases. - Fix several bugs in the optimisation phase (could lead to incorrect FlatZinc and crashes). - Fix a problem with reverse mapper functions when the result of the reverse mapper can be fixed to a constant. Version 2.0.7 ============= Changes: - Improved propagation of Boolean constants in the optimisation phase. This should result in far fewer aliases and improves simplification of conjunctions, disjunctions and clauses. - Add special case handling for integer division by 1. Bug fixes: - Fix FlatZinc generator phase, need to turn all array literal arguments into 1-based single dimensional arrays. - Fix compilation of if-then-else expressions with var conditions (which didn't implement proper partiality/totality semantics). Fixes #42. - Provide correct bounds for weak opt var arithmetic. Fixes #51. - Need to be able to handle unflattened annotations. Fixes #53. - Fix generation of output model (needs to ignore items that have been removed previously). - Add missing lb(var set of int) builtin. Fixes #47. - Check that var set declarations have a finite element type. Fixes #46. - Fix translation context for binary operators on arrays. - Need to access IntVal::infinity as a function, otherwise depending on linker etc it may become 0 in some cases. Fixes #40. - Change pretty printer to use one less digit when printing float literals. This fixes #41 (or at least provides a workaround), but some double constants may still be rounded incorrectly when pretty printing and reading them back in. The real fix will be to output hex float literals (coming soon). - Distinguish between generalised comprehensions (iterating over sets) and iterating over arrays. Fixes compilation of comprehensions where iteration over an array is combined with var where clauses. Fixes #45. - Fix bug in creation of output model where sometimes chains of variable definitions could lead to crashes. - Avoi creating mutually recursive definitions in some corner cases, which could cause the compiler to run into infinite loops. - Don't copy vardecl items to output model that are already there. Fixes #44. - Remove domain from array declarations in FlatZinc (avoids problems with domains where holes need to be removed and when there are infinities in the domains) - Fix flattening of equality operator between non-opt and opt vars - Check that model contains a single solve and output item during type checking (previously, multiple output items were not detected and resulted in incorrect .ozn files). - Fix flattening of xor (arguments need to be in mixed context). - Use is_fixed in cumulative definition. - Fix bug where a par right hand side of a variable mentioned in the output would cause a crash. - Fix variable dependency tracking during rewriting in the optimisation phase. Could previously lead to variables being removed that are still required. Fixes #54. Version 2.0.6 ============= Changes: - Add parser support for hexadecimal floating point constants. Bug fixes: - Fix bounds computation for some calls (abs, int_times). - Fix flattening of some array declarations (when right hand side is an identifier). - Add four missing GC locks (could lead to incorrect garbage collection). - Compact output model only after optimisation phase (could lead to incorrect items being removed from output model). Version 2.0.5 ============= Changes: - Improve the standard decomposition for the cumulative constraint. - Better handling of binary operators during type checking and flattening, can sometimes avoid stack overflows (e.g. for large conjunctions). - Make ++ operator left associative (avoid stack overflows in the parser). - Add ::domain annotations to linear constraints generated from multi-dimensional element constraints. - Greatly improved linearisation library. Bug fixes: - Fix recursive function calls that contain let expressions. - Fix compilation of comprehensions inside parametric functions. - Fix a memory leak in solns2out. - Fix a problem in the evaluation of binary operators. - Fix a bug in the flattening of array literals. - Fix a bug that would crash the parser on certain syntax errors in let expressions. Version 2.0.4 ============= Changes: - Models can now be read from standard input (using the "-" or "--input-from-stdin" command line options). Thanks to Sebastian Kosch. - Improved handling of bool2int during FlatZinc generation. Bug fixes: - Fix unification of aliased variables which could sometimes result in variables being removed although had a constraining right hand side. - Fix evaluation of set comprehensions. - Fix command line flag --no-output-ozn - Fix performance problem when evaluating array expressions inside lets. - Fix flattening of bool_xor redefinitions. - Fix partial evaluation of some array access expressions with var indexes. - Fix definition of geost constraint. - User-defined functions are now copied correctly into the output model if they are referenced in the output item. - Set comprehensions are fully evaluated. Version 2.0.3 ============= (Internal release that did not contain some essential fixes) Version 2.0.2 ============= Changes: - The optimiser now removes simple domain constraints from the FlatZinc - The compiler now checks for integer overflows in all built-in operations - Report an error when the FlatZinc or ozn file cannot be opened for writing - Add support for 3d array literals (e.g. [| |1,2|3,4|,|5,6|7,8| |] ) - Add show2d and show3d functions for formatting array output - Add row/col functions for variable arrays (github issue #2) - Introduce builtins for creating random distributions - Add reverse library function - Postpone flattening of some reified constraints - Slightly improved compilation of partial function calls when it can be inferred at compile time that their result is undefined - Allow functions with empty argument lists to be declared as function int: foo(); instead of just function int: foo; - Improve error reporting, in particular for errors in comprehensions - Enable expressions a..b where a and b are integer variables - Add redundant_constraint and symmetry_breaking_constraint builtins, these can be rewritten by solver libraries to allow e.g. local search solvers to ignore redundant constraints. - Improve flattening of predicates that simply return their arguments (makes the redundant_constraint and symmetry_breaking_constraint predicates work in more situations). - Replace command line option --only-range-domains by optional boolean value so that solver libraries can set the flag directly in their redefinitions file. - Stop flattening immediately when a model has been found to contain an inconsistency. - Improve flattening of array access expressions, in particular for nested array accesses that can be combined into a single element constraint - Add command line option -s or --statistics to print statistics about the generated FlatZinc - Improve bounds computation for if-then-else expressions - Clause arguments are compiled in positive and negative contexts instead of mixed. That means that predicates that introduce free variables can now be used in the positive part of a clause. Bug fixes: - Fix simplification of linear expressions, negative coefficients could sometimes result in incorrect bounds - Fix bounds computation for unary minus operator - Add missing par set comparison builtins - Fix bounds computation for extended comprehension syntax - Fix a bug in the garbage collector that could sometimes lead to premature deletion of expressions - Fix bounds computation for set difference - Fix duplication of some arrays in the FlatZinc (github issue #3) - Fix bounds inference for variables bound to empty sets (github bug #3) - Fix bug in error reporting function, which would sometimes not report the entire call stack - Fix the generation of fresh variable names for generator expressions - Fix subtype check to allow empty arrays as subtype of arrays of sets - Fix crash when using assert/2 - Fix bug when function used in output referred to par variable - Fix bug in type checker, the detection of cyclic definitions was not correct and could lead to stack overflows - Fix parser to accept expressions with two consecutive array accesses (like x[3][4], which are valid MiniZinc if x is an array of sets) - Fix error reporting when an evaluation error occurs within a comprehension generator - Report type error on some ambiguous function calls - Report type error on var sets with element type other than int - Report type error when trying to coerce a var set into an array - Report error when calling function with a value that is outside the declared parameter bounds - Fix arg_sort builtin to implement the correct semantics - Fix sort_by builtin to sort in non-decreasing order, and work with floats - Fix bug in type checker, now automatic coercions in functions defined with type variables (like the comparison operators) work correctly - Check that index sets match for arrays assigned in let expressions - Fix bug in bounds inference for integer expressions with annotations - Fix propagation of defines_var annotation to be pushed through calls - Fix parser to accept empty 2d and 3d array literals - Fix flattening to remove defines_var annotations with par argument, e.g. defines_var(2), which could be introduced by the optimisation pass - Fix output model creation for variables that have been redefined, and remove more unused variables from the FlatZinc. - Fix bug in the garbage collector that could result in function items not being kept alive in rare cases. Version 2.0.1 ============= Major bugs and changes: - Fix optimisation phase, which was previously incorrectly removing variables - Add support for trigonometric functions (built-ins were missing in 2.0.0) and pow (var versions were missing) - Fix equality operator on par arrays - All expressions in output model are now made par - Improve bounds computation for float variables - Fix translation of functions that need automatic coercion of their return value - Fix the array_lb and array_ub builtins, which would return incorrect bounds in some cases Minor bugs and changes: - Add space between "array" and "[" in the pretty printer, to be compatible with 1.6 output - Output all par declarations before the var declarations in FlatZinc - Fix parser, which could sometimes crash on invalid input - Improve efficiency of bounds computation on some float expressions - Add special case handling for division by 1 - Add missing float_times definition to the flatzinc builtins - Use correct version of var_dom for float variables - Output information about which files are included in verbose mode - Only compute bounds for "then" expressions if the "if" is not fixed to false Version 2.0.0 ============= MiniZinc 2.0 contains many new features and is based on a complete rewrite of the MiniZinc-to-FlatZinc compiler. If you are currently using the previous version 1.6, the new tools can be used as drop-in replacements. The generated FlatZinc is compatible with version 1.6, so all FlatZinc solvers should work without changes. ** MiniZinc language changes ** - MiniZinc now supports user-defined functions. Details have been published in the paper "MiniZinc with Functions". Both functions and predicates can be recursive. - MiniZinc now supports option types. Details have been published in the paper "Modelling with Option Types in MiniZinc". - Let expressions have been generalised. They can now contain constraint items in addition to variable declarations. - Array index sets can be declared using arbitrary set expressions as long as they evaluate to contiguous ranges. - The if-then-else expression has been generalised to allow the condition to be a var bool expression (instead of only par bool). - Array and set comprehensions as well as generator calls can now iterate over variables and use var bool where conditions. - Any bool expression can now automatically coerce to an int expression, likewise for int and float. This means that you don't have to write bool2int or int2float in your models any more. - Equality constraints can now be posted between array expressions. - Arbitrary expressions can now be included ("interpolated") into strings, using the syntax "some text \(e) some more text", where e is any expression. It is the same as writing "some text "++show(e)++" some more text". ** New built-in functions ** Array functions: array1d, arrayXd, row, col, has_index, has_element, sort_by, sort, arg_sort, arg_min, arg_max ** New global constraints ** - arg_max, arg_min - arg_sort - k-dimensional diffn - disjunctive - geost - knapsack - network_flow - regular with NFAs - symmetric all different - optional scheduling constraints: alternative, span, disjunctive, cumulative - functional versions of many global constraints ** New tool chain ** - There are a few new builtins that solvers can reimplement, these are listed in the redefinitions-2.0 file. - Include items use a different method for finding included files. Paths are now interpreted as relative to the file that has the include item. That way, the mzn2fzn compiler can be called from a different working directory. - A new tool, mzn2doc, can produce html output from the documentation comments. The MiniZinc distribution contains the documentation for global constraints and builtins generated directly from the library source code. libminizinc-2.4.2/CMakeLists.txt000066400000000000000000000074541360574160400166060ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.4.0) # ------------------------------------------------------------------------------------------------------------------- # -- Project information and versioning. project(libminizinc VERSION 2.4.2 LANGUAGES CXX C) if(NOT BUILD_REF) set(BUILD_REF "") endif() # ------------------------------------------------------------------------------------------------------------------- # -- Project build options # Driver compilation selection option(USE_CPLEX "Enable the CPLEX solving target" TRUE) option(USE_GEAS "Enable the Geas solving target" TRUE) option(USE_GECODE "Enable the Gecode solving target" TRUE) option(USE_GUROBI "Enable the Gurobi solving target" TRUE) option(USE_OSICBC "Enable the Osi CBC solving target" TRUE) option(USE_SCIP "Enable the SCIP solving target" TRUE) option(USE_XPRESS "Enable the Xpress solving target" TRUE) # Static vs. Dynamic linking option(CPLEX_PLUGIN "Build CPLEX binding as a plugin" ON) option(GUROBI_PLUGIN "Build Gurobi binding as a plugin" ON) # Enforce non proprietary build option(USE_PROPRIETARY "Enable static linking of proprietary solvers" OFF) if(NOT USE_PROPRIETARY) set(CPLEX_PLUGIN ON) set(GUROBI_PLUGIN ON) set(USE_SCIP OFF) endif() # Export compile commands (useful when working with visual studio code) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # ------------------------------------------------------------------------------------------------------------------- # -- CMake initialisation # Fix library suffixes for Web Assembly platform include(cmake/support/emscripten_setup.cmake) # Try to find possible dependencies list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) if(POLICY CMP0074) cmake_policy(SET CMP0074 NEW) endif(POLICY CMP0074) find_package(CPlex) find_package(Geas) find_package(Gecode 6.0 COMPONENTS Driver Float Int Kernel Minimodel Search Set Support) find_package(Gurobi) find_package(OsiCBC) find_package(SCIP CONFIG) find_package(Xpress) # Set build type when none is selected set(DEFAULT_BUILD_TYPE "Release") if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.") set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() # ------------------------------------------------------------------------------------------------------------------- # -- Compiler configuration include(cmake/support/ccache_setup.cmake) include(cmake/support/compiler_setup.cmake) configure_file( ${PROJECT_SOURCE_DIR}/include/minizinc/config.hh.in ${PROJECT_BINARY_DIR}/include/minizinc/config.hh ) install( FILES ${PROJECT_BINARY_DIR}/include/minizinc/config.hh DESTINATION include/minizinc ) # ------------------------------------------------------------------------------------------------------------------- # -- MiniZinc compilation targets. find_package(Threads REQUIRED) include_directories(${PROJECT_SOURCE_DIR}/include) include_directories(${PROJECT_BINARY_DIR}/include) # Libraries include(cmake/targets/libmzn.cmake) # Executables include(cmake/targets/minizinc.cmake) include(cmake/targets/mzn2doc.cmake) # ------------------------------------------------------------------------------------------------------------------- # -- Platform Specific configuration include(cmake/support/config_emscripten.cmake) # ------------------------------------------------------------------------------------------------------------------- # -- CMake configuration generation include(cmake/support/config_export.cmake) include(cmake/support/config_output.cmake) libminizinc-2.4.2/LICENSE.txt000066400000000000000000000410351360574160400156620ustar00rootroot00000000000000If not noted otherwise in individual file headers, all files that make up the libminizinc distribution are released under the Mozilla Public License Version 2.0, a copy of which can be found below. Mozilla Public License Version 2.0 ================================== 1. Definitions -------------- 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or (b) any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions -------------------------------- 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: (a) for any code that a Contributor has removed from Covered Software; or (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities ------------------- 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation --------------------------------------------------- If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination -------------- 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. ************************************************************************ * * * 6. Disclaimer of Warranty * * ------------------------- * * * * Covered Software is provided under this License on an "as is" * * basis, without warranty of any kind, either expressed, implied, or * * statutory, including, without limitation, warranties that the * * Covered Software is free of defects, merchantable, fit for a * * particular purpose or non-infringing. The entire risk as to the * * quality and performance of the Covered Software is with You. * * Should any Covered Software prove defective in any respect, You * * (not any Contributor) assume the cost of any necessary servicing, * * repair, or correction. This disclaimer of warranty constitutes an * * essential part of this License. No use of any Covered Software is * * authorized under this License except under this disclaimer. * * * ************************************************************************ ************************************************************************ * * * 7. Limitation of Liability * * -------------------------- * * * * Under no circumstances and under no legal theory, whether tort * * (including negligence), contract, or otherwise, shall any * * Contributor, or anyone who distributes Covered Software as * * permitted above, be liable to You for any direct, indirect, * * special, incidental, or consequential damages of any character * * including, without limitation, damages for lost profits, loss of * * goodwill, work stoppage, computer failure or malfunction, or any * * and all other commercial damages or losses, even if such party * * shall have been informed of the possibility of such damages. This * * limitation of liability shall not apply to liability for death or * * personal injury resulting from such party's negligence to the * * extent applicable law prohibits such limitation. Some * * jurisdictions do not allow the exclusion or limitation of * * incidental or consequential damages, so this exclusion and * * limitation may not apply to You. * * * ************************************************************************ 8. Litigation ------------- Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous ---------------- This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License --------------------------- 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice ------------------------------------------- This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice --------------------------------------------------------- This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. libminizinc-2.4.2/README.txt000066400000000000000000000007351360574160400155370ustar00rootroot00000000000000MiniZinc ======== This package contains the MiniZinc constraint modelling language and tool chain. For the full documentation, including installation and compilation instructions, see http://minizinc.org/doc-latest/index.html. ** Bugs ** If you encounter any problems with MiniZinc, please use the MiniZinc discussion forum https://www.minizinc.org/forum.html and the bug tracker at https://github.com/MiniZinc/libminizinc/issues to report any issues or feature requests. libminizinc-2.4.2/cmake/000077500000000000000000000000001360574160400151145ustar00rootroot00000000000000libminizinc-2.4.2/cmake/modules/000077500000000000000000000000001360574160400165645ustar00rootroot00000000000000libminizinc-2.4.2/cmake/modules/FindCPlex.cmake000066400000000000000000000046331360574160400214100ustar00rootroot00000000000000# - Try to find CPLEX # Once done this will define # CPLEX_FOUND - System has CPLEX # CPLEX_INCLUDE_DIRS - The CPLEX include directories # CPLEX_LIBRARIES - The libraries needed to use CPLEX # CPLEX_COMPILE_FLAGS - The definitions required to compile with CPLEX # User can set CPlex_ROOT to the preferred installation prefix set(CPLEX_COMPILE_FLAGS "-fPIC -fno-strict-aliasing -fexceptions -DNDEBUG") set(CPLEX_VERSIONS 129 128 1271 127 1263 1262 1261 126) foreach(VERSION ${CPLEX_VERSIONS}) list(APPEND CPLEX_DEFAULT_LOC "/opt/ibm/ILOG/CPLEX_Studio${VERSION}") list(APPEND CPLEX_DEFAULT_LOC "/opt/IBM/ILOG/CPLEX_Studio${VERSION}") list(APPEND CPLEX_DEFAULT_LOC "C:\\Program Files\\IBM\\ILOG\\CPLEX_Studio${VERSION}") list(APPEND CPLEX_DEFAULT_LOC "C:\\Program Files (x86)\\IBM\\ILOG\\CPLEX_Studio${VERSION}") list(APPEND CPLEX_DEFAULT_LOC "$ENV{HOME}/Applications/IBM/ILOG/CPLEX_Studio${VERSION}") list(APPEND CPLEX_DEFAULT_LOC "/Applications/IBM/ILOG/CPLEX_Studio${VERSION}") list(APPEND CPLEX_LIB_NAMES cplex${VERSION}) endforeach(VERSION) find_path(CPLEX_INCLUDE ilcplex/cplex.h HINTS ${CPLEX_DEFAULT_LOC} PATH_SUFFIXES include cplex/include) if(CPLEX_PLUGIN) include(CheckIncludeFiles) # TODO: Cleanup this mess check_include_files(dlfcn.h HAS_DLFCN_H) check_include_files(Windows.h HAS_WINDOWS_H) if(HAS_DLFCN_H) find_library(CPLEX_LIBRARY dl) elseif(HAS_WINDOWS_H) set(CPLEX_LIBRARY ${CPLEX_INCLUDE}) endif() else() foreach(CPLEX_LIB ${CPLEX_LIB_NAMES}) find_library(CPLEX_LIBRARY NAMES cplex ${CPLEX_LIB} HINTS ${CPLEX_DEFAULT_LOC} PATH_SUFFIXES lib/x86-64_linux/static_pic lib/x86-64_osx/static_pic lib/x64_windows_vs2013/stat_mda cplex/lib/x86-64_linux/static_pic cplex/lib/x86-64_osx/static_pic cplex/lib/x64_windows_vs2013/stat_mda) if(NOT "${CPLEX_LIBRARY}" STREQUAL "CPLEX_LIBRARY-NOTFOUND") break() endif() endforeach(CPLEX_LIB) endif() include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set CBC_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(CPlex DEFAULT_MSG CPLEX_INCLUDE CPLEX_LIBRARY) if(CPLEX_PLUGIN AND HAS_WINDOWS_H AND NOT HAS_DLFCN_H) unset(CPLEX_LIBRARY) endif() mark_as_advanced(CPLEX_INCLUDE CPLEX_LIBRARY) set(CPLEX_LIBRARIES ${CPLEX_LIBRARY}) set(CPLEX_INCLUDE_DIRS ${CPLEX_INCLUDE}) libminizinc-2.4.2/cmake/modules/FindGeas.cmake000066400000000000000000000021071360574160400212460ustar00rootroot00000000000000# - Try to find Geas # Once done this will define # GEAS_FOUND - System has Geas # GEAS_INCLUDE_DIRS - The Geas include directories # GEAS_LIBRARIES - The libraries needed to use Geas # User can set Geas_ROOT to the preferred installation prefix # Imported target Geas will be created for linking purposes find_path( GEAS_INCLUDE geas/c/geas.h PATH_SUFFIXES include ) find_library( GEAS_LIBRARY NAMES geas libgeas PATH_SUFFIXES lib ) include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set GEAS_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(Geas FOUND_VAR GEAS_FOUND REQUIRED_VARS GEAS_INCLUDE GEAS_LIBRARY FAIL_MESSAGE "Could NOT find Geas, use GEAS_ROOT to hint its location" ) mark_as_advanced(GEAS_INCLUDE GEAS_LIBRARY) if(GEAS_FOUND) add_library(Geas UNKNOWN IMPORTED) set_target_properties(Geas PROPERTIES IMPORTED_LOCATION ${GEAS_LIBRARY} INTERFACE_INCLUDE_DIRECTORIES ${GEAS_INCLUDE} ) endif() set(GEAS_LIBRARIES ${GEAS_LIBRARY}) set(GEAS_INCLUDE_DIRS ${GEAS_INCLUDE}) libminizinc-2.4.2/cmake/modules/FindGecode.cmake000066400000000000000000000063051360574160400215610ustar00rootroot00000000000000# - Try to find Gecode # Once done this will define # GECODE_FOUND - System has Gecode # GECODE_INCLUDE_DIRS - The Gecode include directories # GECODE_LIBRARIES - The libraries needed to use Gecode # GECODE_TARGETS - The names of imported targets created for gecode # User can set Gecode_ROOT to the preferred installation prefix find_path(GECODE_INCLUDE gecode/kernel.hh PATH_SUFFIXES include) find_file(GECODE_CONFIG_LOC gecode/support/config.hpp HINTS ${GECODE_INCLUDE} PATH_SUFFIXES include) if(NOT "${GECODE_CONFIG_LOC}" STREQUAL "GECODE_CONFIG_LOC-NOTFOUND") file(READ "${GECODE_CONFIG_LOC}" GECODE_CONFIG) string(REGEX MATCH "\#define GECODE_VERSION \"([0-9]+.[0-9]+.[0-9]+)\"" _ "${GECODE_CONFIG}") set(GECODE_VERSION "${CMAKE_MATCH_1}") string(REGEX MATCH "\#define GECODE_LIBRARY_VERSION \"([0-9]+-[0-9]+-[0-9]+)\"" _ "${GECODE_CONFIG}") set(GECODE_LIBRARY_VERSION "${CMAKE_MATCH_1}") string(REGEX MATCH "\#define GECODE_STATIC_LIBS ([0-9]+)" _ "${GECODE_CONFIG}") set(GECODE_STATIC_LIBS "${CMAKE_MATCH_1}") string(REGEX MATCH "\#define GECODE_HAS_GIST" GECODE_HAS_GIST "${GECODE_CONFIG}") string(REGEX MATCH "\#define GECODE_HAS_MPFR" GECODE_HAS_MPFR "${GECODE_CONFIG}") endif() set(GECODE_COMPONENTS Driver Flatzinc Float Int Kernel Minimodel Search Set Support) if(GECODE_HAS_GIST) list(APPEND GECODE_COMPONENTS Gist) endif() foreach(GECODE_COMP ${GECODE_COMPONENTS}) # Try to find gecode library string(TOLOWER "gecode${GECODE_COMP}" GECODE_LIB) set(GECODE_LIB_LOC "GECODE_LIB_LOC-NOTFOUND") find_library(GECODE_LIB_LOC NAMES ${GECODE_LIB} lib${GECODE_LIB} ${GECODE_LIB}-${GECODE_LIBRARY_VERSION}-r-x64 ${GECODE_LIB}-${GECODE_LIBRARY_VERSION}-d-x64 HINTS ${GECODE_INCLUDE} PATH_SUFFIXES lib) if(NOT "${GECODE_LIB_LOC}" STREQUAL "GECODE_LIB_LOC-NOTFOUND") list(APPEND GECODE_LIBRARY ${GECODE_LIB_LOC}) add_library(Gecode::${GECODE_COMP} UNKNOWN IMPORTED) set_target_properties(Gecode::${GECODE_COMP} PROPERTIES IMPORTED_LOCATION ${GECODE_LIB_LOC} INTERFACE_INCLUDE_DIRECTORIES ${GECODE_INCLUDE}) set(Gecode_FIND_REQUIRED_${GECODE_COMP} TRUE) set(Gecode_${GECODE_COMP}_FOUND TRUE) endif() endforeach(GECODE_COMP) if(WIN32 AND GECODE_HAS_GIST AND GECODE_STATIC_LIBS) find_package(Qt5 QUIET COMPONENTS Core Gui Widgets PrintSupport) set_target_properties(Gecode::Gist PROPERTIES INTERFACE_LINK_LIBRARIES "Qt5::Core;Qt5::Gui;Qt5::Widgets;Qt5::PrintSupport") endif() unset(GECODE_REQ_LIBS) unset(GECODE_LIB_WIN) unset(GECODE_LIB_LOC) if(GECODE_LIBRARY AND GECODE_HAS_MPFR) find_package(MPFR) list(APPEND GECODE_LIBRARY ${MPFR_LIBRARIES}) list(APPEND GECODE_TARGETS ${MPFR_LIBRARIES}) endif() include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set GECODE_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args( Gecode REQUIRED_VARS GECODE_INCLUDE GECODE_LIBRARY VERSION_VAR GECODE_VERSION HANDLE_COMPONENTS ) mark_as_advanced(GECODE_INCLUDE GECODE_LIBRARY) set(GECODE_LIBRARIES ${GECODE_LIBRARY}) set(GECODE_INCLUDE_DIRS ${GECODE_INCLUDE}) libminizinc-2.4.2/cmake/modules/FindGurobi.cmake000066400000000000000000000043551360574160400216250ustar00rootroot00000000000000# - Try to find Gurobi # Once done this will define # GUROBI_FOUND - System has GUROBI # GUROBI_INCLUDE_DIRS - The GUROBI include directories # GUROBI_LIBRARIES - The libraries needed to use GUROBI # GUROBI_COMPILE_FLAGS - The definitions required to compile with GUROBI # User can set Gurobi_ROOT to the preferred installation prefix option(GUROBI_PLUGIN "Build Gurobi binding as a plugin" ON) set(GUROBI_COMPILE_FLAGS "-fPIC -fno-strict-aliasing -fexceptions -DNDEBUG") set(GUROBI_VERSIONS 900 811 810 801 752 702) foreach(VERSION ${GUROBI_VERSIONS}) list(APPEND GUROBI_DEFAULT_LOC "/opt/gurobi${VERSION}/linux64") list(APPEND GUROBI_DEFAULT_LOC "/opt/gurobi${VERSION}/linux64") list(APPEND GUROBI_DEFAULT_LOC "C:\\gurobi${VERSION}\\win64") list(APPEND GUROBI_DEFAULT_LOC "C:\\gurobi${VERSION}\\win32") list(APPEND GUROBI_DEFAULT_LOC "/Library/gurobi${VERSION}/mac64") string(SUBSTRING ${VERSION} 0 2 VERSION) list(APPEND GUROBI_LIB_NAMES gurobi${VERSION}) endforeach(VERSION) find_path(GUROBI_INCLUDE gurobi_c.h PATHS $ENV{GUROBI_HOME} HINTS ${GUROBI_DEFAULT_LOC} PATH_SUFFIXES include) if(GUROBI_PLUGIN) include(CheckIncludeFiles) # TODO: Cleanup this mess check_include_files(dlfcn.h HAS_DLFCN_H) check_include_files(Windows.h HAS_WINDOWS_H) if(HAS_DLFCN_H) find_library(GUROBI_LIBRARY dl) elseif(HAS_WINDOWS_H) set(GUROBI_LIBRARY ${GUROBI_INCLUDE}) endif() else() foreach(GUROBI_LIB ${GUROBI_LIB_NAMES}) find_library(GUROBI_LIBRARY NAMES ${GUROBI_LIB} HINTS $ENV{GUROBI_HOME} PATHS ${GUROBI_DEFAULT_LOC} PATH_SUFFIXES lib) if(NOT "${GUROBI_LIBRARY}" STREQUAL "GUROBI_LIBRARY-NOTFOUND") break() endif() endforeach(GUROBI_LIB) endif() include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set CBC_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(Gurobi DEFAULT_MSG GUROBI_INCLUDE GUROBI_LIBRARY) if(GUROBI_PLUGIN AND HAS_WINDOWS_H AND NOT HAS_DLFCN_H) unset(GUROBI_LIBRARY) endif() mark_as_advanced(GUROBI_INCLUDE GUROBI_LIBRARY) set(GUROBI_LIBRARIES ${GUROBI_LIBRARY}) set(GUROBI_INCLUDE_DIRS ${GUROBI_INCLUDE}) libminizinc-2.4.2/cmake/modules/FindMPFR.cmake000066400000000000000000000014111360574160400211300ustar00rootroot00000000000000### Try to find MPFR # Once done this will define # MPFR_FOUND - System has MPFR # MPFR_INCLUDE_DIRS - The MPFR include directories # MPFR_LIBRARIES - The libraries needed to use MPFR find_path(MPFR_INCLUDE NAMES mpfr.h PATHS $ENV{GMPDIR} $ENV{MPFRDIR} ${INCLUDE_INSTALL_DIR}) find_library(MPFR_LIBRARY mpfr PATHS $ENV{GMPDIR} $ENV{MPFRDIR} ${LIB_INSTALL_DIR}) include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set MPFR_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(MPFR DEFAULT_MSG MPFR_LIBRARY MPFR_INCLUDE) mark_as_advanced(MPFR_INCLUDE MPFR_LIBRARY) set(MPFR_INCLUDES ${MPFR_INCLUDE}) set(MPFR_LIBRARIES ${MPFR_LIBRARY}) libminizinc-2.4.2/cmake/modules/FindOsiCBC.cmake000066400000000000000000000054471360574160400214430ustar00rootroot00000000000000# - Try to find CBC # Once done this will define # OSICBC_FOUND - System has CBC # OSICBC_INCLUDE_DIRS - The CBC include directories # OSICBC_LIBRARIES - The libraries needed to use CBC # GOSICBC_TARGETS - The names of imported targets created for CBC # User can set OsiCBC_ROOT to the preferred installation prefix set(OSICBC_FIND_FILES coin/CbcSolver.hpp coin/CglPreProcess.hpp coin/ClpConfig.h coin/CoinSignal.hpp coin/OsiClpSolverInterface.hpp coin/OsiSolverInterface.hpp) foreach(OSICBC_FILE ${OSICBC_FIND_FILES}) set(OSICBC_FILE_LOC "OSICBC_LIB_LOC-NOTFOUND") find_path(OSICBC_FILE_LOC ${OSICBC_FILE} PATH_SUFFIXES cbc cgl clp coinutils osi include) if("${OSICBC_FILE_LOC}" STREQUAL "OSICBC_FILE_LOC-NOTFOUND") # message(STATUS "OsiCBC: Could not find file `${OSICBC_FILE}`") set(OSICBC_INCLUDE "") break() endif() list(APPEND OSICBC_INCLUDE ${OSICBC_FILE_LOC}) # Add "/coin" for CBC internal dependencies list(APPEND OSICBC_INCLUDE ${OSICBC_FILE_LOC}/coin) endforeach(OSICBC_FILE) list(REMOVE_DUPLICATES OSICBC_INCLUDE) unset(OSICBC_FIND_FILES) unset(OSICBC_FILE_LOC) if(WIN32 AND NOT UNIX) set(OSICBC_REQ_LIBS Osi OsiClp OsiCbc Clp Cgl Cbc CbcSolver CoinUtils) else() set(OSICBC_REQ_LIBS CbcSolver Cbc Cgl OsiClp Clp Osi CoinUtils) endif() foreach(OSICBC_LIB ${OSICBC_REQ_LIBS}) set(OSICBC_LIB_LOC "OSICBC_LIB_LOC-NOTFOUND") find_library(OSICBC_LIB_LOC NAMES ${OSICBC_LIB} lib${OSICBC_LIB} PATH_SUFFIXES lib) if("${OSICBC_LIB_LOC}" STREQUAL "OSICBC_LIB_LOC-NOTFOUND") # message(STATUS "OsiCBC: Could not find library `${OSICBC_LIB}`") set(OSICBC_LIBRARY "") break() endif() list(APPEND OSICBC_LIBRARY ${OSICBC_LIB_LOC}) add_library(${OSICBC_LIB} UNKNOWN IMPORTED) set_target_properties(${OSICBC_LIB} PROPERTIES IMPORTED_LOCATION ${OSICBC_LIB_LOC} INTERFACE_INCLUDE_DIRECTORIES "${OSICBC_INCLUDE}") list(APPEND OSICBC_TARGETS ${OSICBC_LIB}) endforeach(OSICBC_LIB) unset(OSICBC_REQ_LIBS) unset(OSICBC_LIB_LOC) if(UNIX AND NOT WIN32 AND NOT DEFINED EMSCRIPTEN) find_package(ZLIB) if(NOT ZLIB_FOUND) message(STATUS "OsiCBC: Missing dependency `Zlib`") set(OSICBC_LIBRARY "") else() list(APPEND OSICBC_LIBRARY ${ZLIB_LIBRARIES}) list(APPEND OSICBC_TARGETS ${ZLIB_LIBRARIES}) endif() endif() include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set CBC_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(OsiCBC FOUND_VAR OSICBC_FOUND REQUIRED_VARS OSICBC_INCLUDE OSICBC_LIBRARY FAIL_MESSAGE "Could NOT find OsiCBC, use OsiCBC_ROOT to hint its location" ) mark_as_advanced(OSICBC_INCLUDE OSICBC_LIBRARY) set(OSICBC_LIBRARIES ${OSICBC_LIBRARY}) set(OSICBC_INCLUDE_DIRS ${OSICBC_INCLUDE}) libminizinc-2.4.2/cmake/modules/FindXpress.cmake000066400000000000000000000027721360574160400216630ustar00rootroot00000000000000# - Try to find FICO Xpress # Once done this will define # XPRESS_FOUND - System has FICO Xpress # XPRESS_INCLUDE_DIRS - The FICO Xpress include directories # XPRESS_LIBRARIES - The libraries needed to use FICO Xpress # User can set Xpress_ROOT to the preferred installation prefix #TODO: Check default installation locations find_path(XPRESS_INCLUDE xprs.h PATHS $ENV{XPRESSDIR} $ENV{XPRESS} $ENV{XPRESS_DIR} HINTS /opt/xpressmp C:/xpressmp PATH_SUFFIXES include) foreach(XPRESS_LIB xprb xprs) set(XPRESS_LIB_LOC "XPRESS_LIB_LOC-NOTFOUND") find_library(XPRESS_LIB_LOC NAMES ${XPRESS_LIB} lib${XPRESS_LIB} PATHS $ENV{XPRESSDIR} $ENV{XPRESS} $ENV{XPRESS_DIR} HINTS /opt/xpressmp C:/xpressmp PATH_SUFFIXES lib) if("${XPRESS_LIB_LOC}" STREQUAL "XPRESS_LIB_LOC-NOTFOUND") # message(STATUS "FICO Xpres: Could not find library `${XPRESS_LIB}`") set(XPRESS_LIBRARY "") break() endif() list(APPEND XPRESS_LIBRARY ${XPRESS_LIB_LOC}) endforeach(XPRESS_LIB) include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set XPRESS_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(Xpress FOUND_VAR XPRESS_FOUND REQUIRED_VARS XPRESS_INCLUDE XPRESS_LIBRARY FAIL_MESSAGE "Could NOT find Xpress, use Xpress_ROOT to hint its location" ) mark_as_advanced(XPRESS_INCLUDE XPRESS_LIBRARY) set(XPRESS_LIBRARIES ${XPRESS_LIBRARY}) set(XPRESS_INCLUDE_DIRS ${XPRESS_INCLUDE}) libminizinc-2.4.2/cmake/scripts/000077500000000000000000000000001360574160400166035ustar00rootroot00000000000000libminizinc-2.4.2/cmake/scripts/md5_gen.cmake000066400000000000000000000044121360574160400211240ustar00rootroot00000000000000# Script to update the cached lexer and parser # Run after modifying lexer.lxx and/or parser.yxx # # 1. generate lexer and parser by building libminizinc # 2. run cmake -DPROJECT_SOURCE_DIR=. -DPROJECT_BINARY_DIR=build -P cmake/scripts/md5_gen.cmake # replacing . and build with the source and binary directory # add -DFORCE=ON to force the renewing of generated files when md5's still match. option(FORCE "Force the renewing of generated files" OFF) macro(MD5 filename md5sum) file(READ "${filename}" RAW_MD5_FILE) string(REGEX REPLACE "\r" "" STRIPPED_MD5_FILE "${RAW_MD5_FILE}") string(MD5 ${md5sum} "${STRIPPED_MD5_FILE}") endmacro(MD5) # When updating the cached files, update MD5 sums defined in this file include(../../lib/cached/md5_cached.cmake) MD5("../../lib/lexer.lxx" lexer_lxx_md5) MD5("../../lib/parser.yxx" parser_yxx_md5) MD5("../../lib/support/regex/lexer.lxx" regex_lexer_lxx_md5) MD5("../../lib/support/regex/parser.yxx" regex_parser_yxx_md5) if(FORCE OR (NOT "${lexer_lxx_md5}" STREQUAL "${lexer_lxx_md5_cached}")) file(COPY "${PROJECT_BINARY_DIR}/lexer.yy.cpp" DESTINATION "../../lib/cached") endif() if(FORCE OR (NOT "${parser_yxx_md5}" STREQUAL "${parser_yxx_md5_cached}")) file(COPY "${PROJECT_BINARY_DIR}/parser.tab.cpp" DESTINATION "../../lib/cached") file(COPY "${PROJECT_BINARY_DIR}/include/minizinc/parser.tab.hh" DESTINATION "../../lib/cached/minizinc") endif() if(FORCE OR (NOT "${regex_lexer_lxx_md5}" STREQUAL "${regex_lexer_lxx_md5_cached}")) file(COPY "${PROJECT_BINARY_DIR}/regex_lexer.yy.cpp" DESTINATION "../../lib/cached") endif() if(FORCE OR (NOT "${regex_parser_yxx_md5}" STREQUAL "${regex_parser_yxx_md5_cached}")) file(COPY "${PROJECT_BINARY_DIR}/regex_parser.tab.cpp" DESTINATION "../../lib/cached") file(COPY "${PROJECT_BINARY_DIR}/include/minizinc/support/regex_parser.tab.hh" DESTINATION "../../lib/cached/minizinc/support") endif() set(MD5_TEMPLATE "set(lexer_lxx_md5_cached \"${lexer_lxx_md5}\")") set(MD5_TEMPLATE "${MD5_TEMPLATE}\nset(parser_yxx_md5_cached \"${parser_yxx_md5}\")") set(MD5_TEMPLATE "${MD5_TEMPLATE}\nset(regex_lexer_lxx_md5_cached \"${regex_lexer_lxx_md5}\")") set(MD5_TEMPLATE "${MD5_TEMPLATE}\nset(regex_parser_yxx_md5_cached \"${regex_parser_yxx_md5}\")") file(WRITE "../../lib/cached/md5_cached.cmake" ${MD5_TEMPLATE}) libminizinc-2.4.2/cmake/support/000077500000000000000000000000001360574160400166305ustar00rootroot00000000000000libminizinc-2.4.2/cmake/support/ccache_setup.cmake000066400000000000000000000021251360574160400222600ustar00rootroot00000000000000option(USE_CCACHE "Use ccache to speed up compilation when found on the system" TRUE) find_program(CCACHE_PROGRAM ccache) if(USE_CCACHE AND CCACHE_PROGRAM) # Support Unix Makefiles and Ninja set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") # Support for Xcode get_property(RULE_LAUNCH_COMPILE GLOBAL PROPERTY RULE_LAUNCH_COMPILE) if(RULE_LAUNCH_COMPILE AND CMAKE_GENERATOR STREQUAL "Xcode") # Set up wrapper scripts configure_file(cmake/templates/launch-c.in launch-c) configure_file(cmake/templates/launch-cxx.in launch-cxx) execute_process(COMMAND chmod a+rx "${CMAKE_BINARY_DIR}/launch-c" "${CMAKE_BINARY_DIR}/launch-cxx") # Set Xcode project attributes to route compilation through our scripts set(CMAKE_XCODE_ATTRIBUTE_CC "${CMAKE_BINARY_DIR}/launch-c") set(CMAKE_XCODE_ATTRIBUTE_CXX "${CMAKE_BINARY_DIR}/launch-cxx") set(CMAKE_XCODE_ATTRIBUTE_LD "${CMAKE_BINARY_DIR}/launch-c") set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS "${CMAKE_BINARY_DIR}/launch-cxx") endif() endif() libminizinc-2.4.2/cmake/support/compiler_setup.cmake000066400000000000000000000037571360574160400227000ustar00rootroot00000000000000set(CMAKE_CXX_STANDARD 11) option(USE_ADDRESS_SANITIZER "Use GCC Address Sanitizer" OFF) if(USE_ADDRESS_SANITIZER) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") endif() if(APPLE) execute_process(COMMAND xcrun --show-sdk-path OUTPUT_VARIABLE OSX_SYSROOT OUTPUT_STRIP_TRAILING_WHITESPACE) set(CMAKE_OSX_SYSROOT ${OSX_SYSROOT}) set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum OS X deployment version") endif(APPLE) set(CMAKE_REQUIRED_QUIET $) include(CheckCXXCompilerFlag) set(SAFE_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") check_cxx_compiler_flag(-Werror HAS_WERROR) if(HAS_WERROR) set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror") endif() check_cxx_source_compiles("int main(void) { static __thread int x; (void)x; return 0;}" HAS_ATTR_THREAD) if(NOT HAS_ATTR_THREAD) check_cxx_source_compiles("int main(void) { __declspec(thread) static int x; (void)x; return 0;}" HAS_DECLSPEC_THREAD) endif() check_cxx_source_compiles("#include int main(void) { long long int x = atoll(\"123\"); (void)x; }" HAS_ATOLL) check_cxx_source_compiles(" #include #include #include #include #include #include int main (int argc, char* argv[]) { pid_t pid = getpid(); char path[PROC_PIDPATHINFO_MAXSIZE]; (void) proc_pidpath (pid, path, sizeof(path)); return 0; } " HAS_PIDPATH) check_cxx_source_compiles(" #include int main (int argc, char* argv[]) { char path[MAX_PATH]; (void) GetModuleFileName(NULL, path, MAX_PATH); return 0; }" HAS_GETMODULEFILENAME) check_cxx_source_compiles(" #include int main (int argc, char* argv[]) { (void) GetFileAttributes(NULL); return 0; }" HAS_GETFILEATTRIBUTES) check_cxx_source_compiles(" #include int main (int argc, char* argv[]) { (void) memcpy_s(NULL,0,NULL,0); return 0; }" HAS_MEMCPY_S)libminizinc-2.4.2/cmake/support/config_emscripten.cmake000066400000000000000000000063741360574160400233420ustar00rootroot00000000000000if (DEFINED EMSCRIPTEN) add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/CMakeFiles/file_packager.js COMMAND python ${EMSCRIPTEN_ROOT_PATH}/tools/file_packager.py minizinc.data --lz4 --preload ${PROJECT_SOURCE_DIR}/share@/minizinc --from-emcc --js-output=${PROJECT_BINARY_DIR}/CMakeFiles/file_packager.js COMMENT "building data store minizinc.data") set(EMSCRIPTEN_CXX_FLAGS "-s MINIZ_NO_ARCHIVE_APIS -s MINIZ_NO_ZLIB_APIS") set(EMSCRIPTEN_LINK_FLAGS " -s FORCE_FILESYSTEM=1 -s LZ4=1 -s MODULARIZE=1 -s EXTRA_EXPORTED_RUNTIME_METHODS=\"['callMain', 'cwrap', 'FS', 'ENV']\" -s DISABLE_EXCEPTION_CATCHING=0 -s BINARYEN_TRAP_MODE=\"clamp\" -s ALLOW_MEMORY_GROWTH=1 --no-heap-copy") # ------------------------------------------------------------------------------------------------------------------- # -- Web Assembly Configuration. # MiniZinc main executable em_link_pre_js(minizinc ${PROJECT_SOURCE_DIR}/cmake/support/emscripten_file_packager_patch.js) em_link_pre_js(minizinc ${PROJECT_BINARY_DIR}/CMakeFiles/file_packager.js) set_target_properties(minizinc PROPERTIES CXX_FLAGS ${EMSCRIPTEN_CXX_FLAGS}) set_target_properties(minizinc PROPERTIES LINK_FLAGS "-s WASM=1 -s EXPORT_NAME=\"'MINIZINC'\" ${EMSCRIPTEN_LINK_FLAGS}") install(FILES ${PROJECT_BINARY_DIR}/minizinc.wasm DESTINATION bin) install(FILES ${PROJECT_BINARY_DIR}/minizinc.data DESTINATION bin) # mzn2doc executable em_link_pre_js(mzn2doc ${PROJECT_SOURCE_DIR}/cmake/support/emscripten_file_packager_patch.js) em_link_pre_js(mzn2doc ${PROJECT_BINARY_DIR}/CMakeFiles/file_packager.js) set_target_properties(mzn2doc PROPERTIES CXX_FLAGS ${EMSCRIPTEN_CXX_FLAGS}) set_target_properties(mzn2doc PROPERTIES LINK_FLAGS "-s WASM=1 -s EXPORT_NAME=\"'MZN2DOC'\" ${EMSCRIPTEN_LINK_FLAGS}") install(FILES ${PROJECT_BINARY_DIR}/mzn2doc.wasm DESTINATION bin) # ------------------------------------------------------------------------------------------------------------------- # -- ASM.js (JavaScript) Configuration. # MiniZinc main executable add_executable(minizinc_asm minizinc.cpp) target_link_libraries(minizinc_asm mzn) em_link_pre_js(minizinc_asm ${PROJECT_SOURCE_DIR}/cmake/support/emscripten_file_packager_patch.js) em_link_pre_js(minizinc_asm ${PROJECT_BINARY_DIR}/CMakeFiles/file_packager.js) set_target_properties(minizinc_asm PROPERTIES CXX_FLAGS ${EMSCRIPTEN_CXX_FLAGS}) set_target_properties(minizinc_asm PROPERTIES LINK_FLAGS "-s WASM=0 -s EXPORT_NAME=\"'MINIZINC'\" ${EMSCRIPTEN_LINK_FLAGS}") install(TARGETS minizinc_asm RUNTIME DESTINATION bin) install(FILES $.mem DESTINATION bin) # mzn2doc executable add_executable(mzn2doc_asm mzn2doc.cpp) target_link_libraries(mzn2doc_asm mzn) em_link_pre_js(mzn2doc_asm ${PROJECT_SOURCE_DIR}/cmake/support/emscripten_file_packager_patch.js) em_link_pre_js(mzn2doc_asm ${PROJECT_BINARY_DIR}/CMakeFiles/file_packager.js) set_target_properties(mzn2doc_asm PROPERTIES CXX_FLAGS ${EMSCRIPTEN_CXX_FLAGS}) set_target_properties(mzn2doc_asm PROPERTIES LINK_FLAGS "-s WASM=0 -s EXPORT_NAME=\"'MZN2DOC'\" ${EMSCRIPTEN_LINK_FLAGS}") install(TARGETS mzn2doc_asm RUNTIME DESTINATION bin) install(FILES $.mem DESTINATION bin) endif() libminizinc-2.4.2/cmake/support/config_export.cmake000066400000000000000000000054131360574160400225030ustar00rootroot00000000000000### Export of a CMake configuration for MiniZinc ## This allows for "find_package(minizinc)" if(WIN32 AND NOT CYGWIN) set(DEF_INSTALL_CMAKE_DIR CMake) else() set(DEF_INSTALL_CMAKE_DIR lib/cmake) endif() set(INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files") if(NOT IS_ABSOLUTE "${INSTALL_CMAKE_DIR}") set(INSTALL_CMAKE_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_CMAKE_DIR}") endif() file(RELATIVE_PATH REL_CMAKE_DIR "${CMAKE_INSTALL_PREFIX}" "${INSTALL_CMAKE_DIR}") file(RELATIVE_PATH REL_INCLUDE_DIR "${INSTALL_CMAKE_DIR}" "${CMAKE_INSTALL_PREFIX}/include") # Add external (static) dependencies if(TARGET minizinc_geas) install( FILES cmake/modules/FindGeas.cmake DESTINATION ${REL_CMAKE_DIR} COMPONENT dev ) set(CONF_DEPENDENCIES "${CONF_DEPENDENCIES}find_dependency(Geas)\n") endif() if(TARGET minizinc_gecode) install( FILES cmake/modules/FindGecode.cmake cmake/modules/FindMPFR.cmake DESTINATION ${REL_CMAKE_DIR} COMPONENT dev ) if(GECODE_HAS_GIST) set(_CONF_GIST " Gist") endif() set(CONF_DEPENDENCIES "${CONF_DEPENDENCIES}find_dependency(Gecode 6.0 COMPONENTS Driver Float Int Kernel Minimodel Search Set Support${_CONF_GIST})\n") endif() if(TARGET minizinc_osicbc) install( FILES cmake/modules/FindOsiCBC.cmake DESTINATION ${REL_CMAKE_DIR} COMPONENT dev ) set(CONF_DEPENDENCIES "${CONF_DEPENDENCIES}find_dependency(OsiCBC)\n") endif() # Add all targets to the build-tree export set export(TARGETS mzn FILE "${PROJECT_BINARY_DIR}/libminizincTargets.cmake") # Export the package for use from the build-tree # (this registers the build-tree with a global CMake-registry) export(PACKAGE libminizinc) # Create the libminizincConfig.cmake and libminizincConfigVersion files # ... for the build tree set(CONF_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}") configure_file( cmake/templates/libminizincConfig.cmake.in "${PROJECT_BINARY_DIR}/libminizincConfig.cmake" @ONLY ) # ... for the install tree set(CONF_INCLUDE_DIRS "\${libminizinc_CMAKE_DIR}/${REL_INCLUDE_DIR}") configure_file( cmake/templates/libminizincConfig.cmake.in "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/libminizincConfig.cmake" @ONLY ) # ... for both configure_file( cmake/templates/libminizincConfigVersion.cmake.in "${PROJECT_BINARY_DIR}/libminizincConfigVersion.cmake" @ONLY ) # Install the libminizincConfig.cmake and libminizincConfigVersion.cmake install( FILES "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/libminizincConfig.cmake" "${PROJECT_BINARY_DIR}/libminizincConfigVersion.cmake" DESTINATION ${REL_CMAKE_DIR} COMPONENT dev ) # Install the export set for use with the install-tree install( EXPORT libminizincTargets DESTINATION ${REL_CMAKE_DIR} COMPONENT dev ) libminizinc-2.4.2/cmake/support/config_output.cmake000066400000000000000000000017601360574160400225230ustar00rootroot00000000000000message("\n----- MiniZinc build configuration ----") if(BUILD_REF) set(STR_BUILD_REF "build ${BUILD_REF}") endif() message("MiniZinc version: ${libminizinc_VERSION} ${STR_BUILD_REF}") message("Enabled drivers:") if(TARGET minizinc_cplex) if(CPLEX_PLUGIN) set(STR_CPLEX_PLUGIN " PLUGIN") endif() message("\tCPLEX${STR_CPLEX_PLUGIN}: ${CPLEX_INCLUDE_DIRS}") endif() if(TARGET minizinc_geas) message("\tGeas: ${GEAS_INCLUDE_DIRS}") endif() if(TARGET minizinc_gecode) message("\tGecode ${GECODE_VERSION}: ${GECODE_INCLUDE_DIRS}") endif() if(TARGET minizinc_gurobi) if(GUROBI_PLUGIN) set(STR_GUROBI_PLUGIN " PLUGIN") endif() message("\tGurobi${STR_GUROBI_PLUGIN}: ${GUROBI_INCLUDE_DIRS}") endif() if(TARGET minizinc_osicbc) message("\tOSICBC: ${OSICBC_INCLUDE_DIRS}") endif() if(TARGET minizinc_scip) message("\tSCIP: ${SCIP_INCLUDE_DIRS}") endif() if(TARGET minizinc_xpress) message("\tXPress: ${XPRESS_INCLUDE_DIRS}") endif() message("---------------------------------------\n")libminizinc-2.4.2/cmake/support/emscripten_file_packager_patch.js000066400000000000000000000034521360574160400253560ustar00rootroot00000000000000 function filePackagerPatch_getPreloadedPackageNode(filename) { var fs = require('fs'); var path = require('path'); filename = path.normalize(path.resolve(__dirname, filename)); const buf = fs.readFileSync(filename); // convert to ArrayBuffer return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength); } function filePackagerPatch_isNodeOrShell() { var ENVIRONMENT_IS_WEB = typeof window === 'object'; var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function'; var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function' && !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_WORKER; var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER; return ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL; } if (typeof location === 'undefined') { // create a fake location to overrule the file_packager var location = { pathname: '/' }; } if (filePackagerPatch_isNodeOrShell()) { Module.getPreloadedPackage = Module.getPreloadedPackage || filePackagerPatch_getPreloadedPackageNode; } else { // need a hack to locate relative file in browser settings for the file packager var wrappee = Module.locateFile || function (path, prefix) {return prefix + path}; Module.locateFile = function (path, prefix) { if (prefix || !path.endsWith('.data')) { return wrappee(path, prefix); } // file packager is called before a proper script location decection var base = _scriptDir ? _scriptDir : (typeof importScripts === 'function' ? self.location.href : (typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : '')); if (base.indexOf('blob:') !== 0) { base = base.substr(0, base.lastIndexOf('/') + 1); } else { base = ''; } return wrappee(path, base); }; } libminizinc-2.4.2/cmake/support/emscripten_setup.cmake000066400000000000000000000004111360574160400232170ustar00rootroot00000000000000# Workaround for bug in emscripten cmake: # add .bc (and on macOS .dylib) as library suffixes if (DEFINED EMSCRIPTEN) list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES ".bc") if (CMAKE_HOST_APPLE) list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES ".dylib") endif() endif() libminizinc-2.4.2/cmake/targets/000077500000000000000000000000001360574160400165655ustar00rootroot00000000000000libminizinc-2.4.2/cmake/targets/libminizinc_cplex.cmake000066400000000000000000000017341360574160400232760ustar00rootroot00000000000000### MiniZinc CPLEX Solver Target if(CPLEX_FOUND AND USE_CPLEX) ### Compile target for the CPlex interface add_library(minizinc_cplex OBJECT lib/algorithms/min_cut.cpp solvers/MIP/MIP_cplex_solverfactory.cpp solvers/MIP/MIP_cplex_wrap.cpp solvers/MIP/MIP_solverinstance.cpp include/minizinc/solvers/MIP/MIP_cplex_solverfactory.hh include/minizinc/solvers/MIP/MIP_cplex_wrap.hh include/minizinc/solvers/MIP/MIP_solverinstance.hh ) set_target_properties(minizinc_cplex PROPERTIES COMPILE_FLAGS ${CPLEX_COMPILE_FLAGS}) target_include_directories(minizinc_cplex PRIVATE ${CPLEX_INCLUDE_DIRS}) add_dependencies(minizinc_cplex minizinc_parser) ### Setup correct compilation into the MiniZinc library target_compile_definitions(mzn PRIVATE HAS_CPLEX) target_sources(mzn PRIVATE $) set_target_properties(mzn PROPERTIES COMPILE_FLAGS ${CPLEX_COMPILE_FLAGS}) target_link_libraries(mzn ${CPLEX_LIBRARIES}) endif() libminizinc-2.4.2/cmake/targets/libminizinc_fzn.cmake000066400000000000000000000007261360574160400227600ustar00rootroot00000000000000### MiniZinc FlatZinc Executable Solver Target add_library(minizinc_fzn OBJECT solvers/fzn/fzn_solverfactory.cpp solvers/fzn/fzn_solverinstance.cpp solvers/mzn/mzn_solverfactory.cpp solvers/mzn/mzn_solverinstance.cpp include/minizinc/solvers/fzn_solverfactory.hh include/minizinc/solvers/fzn_solverinstance.hh include/minizinc/solvers/mzn_solverfactory.hh include/minizinc/solvers/mzn_solverinstance.hh ) add_dependencies(minizinc_fzn minizinc_parser) libminizinc-2.4.2/cmake/targets/libminizinc_geas.cmake000066400000000000000000000013721360574160400231000ustar00rootroot00000000000000### MiniZinc Geas Solver Target if(GEAS_FOUND AND USE_GEAS) ### Compile target for the Geas interface add_library(minizinc_geas OBJECT solvers/geas/geas_constraints.cpp solvers/geas/geas_solverfactory.cpp solvers/geas/geas_solverinstance.cpp include/minizinc/solvers/geas/geas_constraints.hh include/minizinc/solvers/geas_solverfactory.hh include/minizinc/solvers/geas_solverinstance.hh ) target_include_directories(minizinc_geas PRIVATE "${GEAS_INCLUDE_DIRS}") add_dependencies(minizinc_geas minizinc_parser) ### Setup correct compilation into the MiniZinc library target_compile_definitions(mzn PRIVATE HAS_GEAS) target_sources(mzn PRIVATE $) target_link_libraries(mzn Geas) endif() libminizinc-2.4.2/cmake/targets/libminizinc_gecode.cmake000066400000000000000000000022071360574160400234050ustar00rootroot00000000000000### MiniZinc Gecode Solver Target if(GECODE_FOUND AND USE_GECODE) ### Compile target for the Gecode interface add_library(minizinc_gecode OBJECT lib/passes/gecode_pass.cpp solvers/gecode/aux_brancher.hh solvers/gecode/fzn_space.cpp solvers/gecode/gecode_constraints.cpp solvers/gecode/gecode_solverfactory.cpp solvers/gecode/gecode_solverinstance.cpp include/minizinc/passes/gecode_pass.hh include/minizinc/solvers/gecode/fzn_space.hh include/minizinc/solvers/gecode/gecode_constraints.hh include/minizinc/solvers/gecode_solverfactory.hh include/minizinc/solvers/gecode_solverinstance.hh ) target_include_directories(minizinc_gecode PRIVATE "${GECODE_INCLUDE_DIRS}") add_dependencies(minizinc_gecode minizinc_parser) ### Setup correct compilation into the MiniZinc library target_compile_definitions(mzn PRIVATE HAS_GECODE) target_sources(mzn PRIVATE $) target_link_libraries(mzn Gecode::Driver Gecode::Float Gecode::Int Gecode::Kernel Gecode::Search Gecode::Set) if(WIN32 AND GECODE_HAS_GIST) target_link_libraries(mzn Gecode::Gist) endif() endif() libminizinc-2.4.2/cmake/targets/libminizinc_gurobi.cmake000066400000000000000000000016151360574160400234500ustar00rootroot00000000000000### MiniZinc Gurobi Solver Target if(GUROBI_FOUND) ### Compile target for the Gurobi interface add_library(minizinc_gurobi OBJECT lib/algorithms/min_cut.cpp lib/utils_savestream.cpp solvers/MIP/MIP_gurobi_solverfactory.cpp solvers/MIP/MIP_gurobi_wrap.cpp solvers/MIP/MIP_solverinstance.cpp include/minizinc/solvers/MIP/MIP_gurobi_solverfactory.hh include/minizinc/solvers/MIP/MIP_gurobi_wrap.hh include/minizinc/solvers/MIP/MIP_solverinstance.hh include/minizinc/solvers/MIP/MIP_solverinstance.hpp ) target_include_directories(minizinc_gurobi PRIVATE ${GUROBI_INCLUDE_DIRS}) add_dependencies(minizinc_gurobi minizinc_parser) ### Setup correct compilation into the MiniZinc library target_compile_definitions(mzn PRIVATE HAS_GUROBI) target_sources(mzn PRIVATE $) target_link_libraries(mzn ${GUROBI_LIBRARIES}) endif() libminizinc-2.4.2/cmake/targets/libminizinc_nl.cmake000066400000000000000000000010071360574160400225650ustar00rootroot00000000000000### MiniZinc NonLinear Executable Solver Target add_library(minizinc_nl OBJECT solvers/nl/nl_components.cpp solvers/nl/nl_file.cpp solvers/nl/nl_solreader.cpp solvers/nl/nl_solverfactory.cpp solvers/nl/nl_solverinstance.cpp include/minizinc/solvers/nl/nl_components.hh include/minizinc/solvers/nl/nl_file.hh include/minizinc/solvers/nl/nl_solreader.hh include/minizinc/solvers/nl/nl_solverfactory.hh include/minizinc/solvers/nl/nl_solverinstance.hh ) add_dependencies(minizinc_nl minizinc_parser) libminizinc-2.4.2/cmake/targets/libminizinc_osicbc.cmake000066400000000000000000000015751360574160400234300ustar00rootroot00000000000000### MiniZinc OsiCBC Solver Target if(OSICBC_FOUND AND USE_OSICBC) ### Compile target for the OsiCBC interface add_library(minizinc_osicbc OBJECT lib/algorithms/min_cut.cpp solvers/MIP/MIP_osicbc_solverfactory.cpp solvers/MIP/MIP_osicbc_wrap.cpp solvers/MIP/MIP_solverinstance.cpp include/minizinc/solvers/MIP/MIP_osicbc_solverfactory.hh include/minizinc/solvers/MIP/MIP_osicbc_wrap.hh include/minizinc/solvers/MIP/MIP_solverinstance.hh include/minizinc/solvers/MIP/MIP_solverinstance.hpp ) target_include_directories(minizinc_osicbc PRIVATE ${OSICBC_INCLUDE_DIRS}) add_dependencies(minizinc_osicbc minizinc_parser) ### Setup correct compilation into the MiniZinc library target_compile_definitions(mzn PRIVATE HAS_OSICBC) target_sources(mzn PRIVATE $) target_link_libraries(mzn ${OSICBC_TARGETS}) endif() libminizinc-2.4.2/cmake/targets/libminizinc_parser.cmake000066400000000000000000000105011360574160400234470ustar00rootroot00000000000000# ------------------------------------------------------------------------------------------------------------------- ## Parser Generation Targets # When updating the cached files, update MD5 sums defined in this file include(${PROJECT_SOURCE_DIR}/lib/cached/md5_cached.cmake) macro(MD5 filename md5sum) file(READ "${filename}" RAW_MD5_FILE) string(REGEX REPLACE "\r" "" STRIPPED_MD5_FILE "${RAW_MD5_FILE}") string(MD5 ${md5sum} "${STRIPPED_MD5_FILE}") endmacro(MD5) find_package(BISON 2.3) find_package(FLEX 2.5) if(BISON_FOUND AND FLEX_FOUND) BISON_TARGET(MZNParser ${PROJECT_SOURCE_DIR}/lib/parser.yxx ${PROJECT_BINARY_DIR}/parser.tab.cpp DEFINES_FILE ${PROJECT_BINARY_DIR}/include/minizinc/parser.tab.hh COMPILE_FLAGS "-p mzn_yy -l" ) file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/include/minizinc/support/) BISON_TARGET(RegExParser ${PROJECT_SOURCE_DIR}/lib/support/regex/parser.yxx ${PROJECT_BINARY_DIR}/regex_parser.tab.cpp DEFINES_FILE ${PROJECT_BINARY_DIR}/include/minizinc/support/regex_parser.tab.hh COMPILE_FLAGS "-p regex_yy -l" ) FLEX_TARGET(MZNLexer ${PROJECT_SOURCE_DIR}/lib/lexer.lxx ${PROJECT_BINARY_DIR}/lexer.yy.cpp COMPILE_FLAGS "-P mzn_yy -L" ) ADD_FLEX_BISON_DEPENDENCY(MZNLexer MZNParser) FLEX_TARGET(RegExLexer ${PROJECT_SOURCE_DIR}/lib/support/regex/lexer.lxx ${PROJECT_BINARY_DIR}/regex_lexer.yy.cpp COMPILE_FLAGS "-P regex_yy -L" ) ADD_FLEX_BISON_DEPENDENCY(RegExLexer RegExParser) else() MD5(${PROJECT_SOURCE_DIR}/lib/parser.yxx parser_yxx_md5) if(NOT "${parser_yxx_md5}" STREQUAL "${parser_yxx_md5_cached}") message(FATAL_ERROR "The file parser.yxx has been modified but bison cannot be run.\n" "If you are sure parser.tab.cpp and minizinc/parser.tab.hh in ${PROJECT_SOURCE_DIR}/lib/cached/ are correct " "then copy parser.yxx's md5 ${parser_yxx_md5} into ${PROJECT_SOURCE_DIR}/lib/cached/md5_cached.cmake" ) endif() MD5(${PROJECT_SOURCE_DIR}/lib/support/regex/parser.yxx regex_parser_yxx_md5) if(NOT "${regex_parser_yxx_md5}" STREQUAL "${regex_parser_yxx_md5_cached}") message(FATAL_ERROR "The file regex/parser.yxx has been modified but bison cannot be run.\n" "If you are sure regex_parser.tab.cpp and minizinc/support/regex_parser.tab.hh in " "${PROJECT_SOURCE_DIR}/lib/cached/ are correct then copy regex_parser.yxx's md5 ${regex_parser_yxx_md5} into " "${PROJECT_SOURCE_DIR}/lib/cached/md5_cached.cmake" ) endif() MD5(${PROJECT_SOURCE_DIR}/lib/lexer.lxx lexer_lxx_md5) if(NOT "${lexer_lxx_md5}" STREQUAL "${lexer_lxx_md5_cached}") message(FATAL_ERROR "The file lexer.lxx has been modified but flex cannot be run.\n" "If you are sure ${PROJECT_SOURCE_DIR}/lib/cached/lexer.yy.cpp is correct then " "copy lexer.lxx's md5 ${lexer_lxx_md5} into ${PROJECT_SOURCE_DIR}/lib/cached/md5_cached.cmake" ) endif() MD5(${PROJECT_SOURCE_DIR}/lib/support/regex/lexer.lxx regex_lexer_lxx_md5) if(NOT "${regex_lexer_lxx_md5}" STREQUAL "${regex_lexer_lxx_md5_cached}") message(FATAL_ERROR "The file regex/lexer.lxx has been modified but flex cannot be run.\n" "If you are sure ${PROJECT_SOURCE_DIR}/lib/cached/regex_lexer.yy.cpp is correct then " "copy regex/lexer.lxx's md5 ${regex_lexer_lxx_md5} into ${PROJECT_SOURCE_DIR}/lib/cached/md5_cached.cmake" ) endif() include_directories(${PROJECT_SOURCE_DIR}/lib/cached) set(BISON_MZNParser_OUTPUTS ${PROJECT_SOURCE_DIR}/lib/cached/parser.tab.cpp ${PROJECT_SOURCE_DIR}/lib/cached/minizinc/parser.tab.hh ) set(BISON_RegExParser_OUTPUTS ${PROJECT_SOURCE_DIR}/lib/cached/regex_parser.tab.cpp ${PROJECT_SOURCE_DIR}/lib/cached/minizinc/support/regex_parser.tab.hh ) set(FLEX_MZNLexer_OUTPUTS ${PROJECT_SOURCE_DIR}/lib/cached/lexer.yy.cpp) set(FLEX_RegExLexer_OUTPUTS ${PROJECT_SOURCE_DIR}/lib/cached/regex_lexer.yy.cpp) endif() if(NOT (GECODE_FOUND AND USE_GECODE)) set(FLEX_RegExLexer_OUTPUTS "") set(BISON_RegExParser_OUTPUTS "") endif() add_library(minizinc_parser OBJECT ${BISON_MZNParser_OUTPUTS} ${FLEX_MZNLexer_OUTPUTS} ${BISON_RegExParser_OUTPUTS} ${FLEX_RegExLexer_OUTPUTS} ) if(GECODE_FOUND AND USE_GECODE) target_include_directories(minizinc_parser PRIVATE "${GECODE_INCLUDE_DIRS}") target_compile_definitions(minizinc_parser PRIVATE HAS_GECODE) endif() libminizinc-2.4.2/cmake/targets/libminizinc_scip.cmake000066400000000000000000000015411360574160400231150ustar00rootroot00000000000000### MiniZinc SCIP Solver Target if(SCIP_FOUND AND USE_SCIP) ### Compile target for the SCIP interface add_library(minizinc_scip OBJECT lib/algorithms/min_cut.cpp solvers/MIP/MIP_scip_solverfactory.cpp solvers/MIP/MIP_scip_wrap.cpp solvers/MIP/MIP_solverinstance.cpp include/minizinc/solvers/MIP/MIP_scip_solverfactory.hh include/minizinc/solvers/MIP/MIP_scip_wrap.hh include/minizinc/solvers/MIP/MIP_solverinstance.hh include/minizinc/solvers/MIP/MIP_solverinstance.hpp ) target_include_directories(minizinc_scip PRIVATE ${SCIP_INCLUDE_DIRS}) add_dependencies(minizinc_scip minizinc_parser) ### Setup correct compilation into the MiniZinc library target_compile_definitions(mzn PRIVATE HAS_SCIP) target_sources(mzn PRIVATE $) target_link_libraries(mzn ${SCIP_LIBRARIES}) endif() libminizinc-2.4.2/cmake/targets/libminizinc_xpress.cmake000066400000000000000000000017521360574160400235070ustar00rootroot00000000000000### MiniZinc FICO Xpress Solver Target if(XPRESS_FOUND AND USE_XPRESS) ### Compile target for the Xpress interface add_library(minizinc_xpress OBJECT lib/algorithms/min_cut.cpp solvers/MIP/MIP_solverinstance.cpp solvers/MIP/MIP_xpress_solverfactory.cpp solvers/MIP/MIP_xpress_wrap.cpp include/minizinc/solvers/MIP/MIP_solverinstance.hh include/minizinc/solvers/MIP/MIP_solverinstance.hpp include/minizinc/solvers/MIP/MIP_xpress_solverfactory.hh include/minizinc/solvers/MIP/MIP_xpress_wrap.hh ) target_include_directories(minizinc_xpress PRIVATE ${XPRESS_INCLUDE_DIRS}) target_link_libraries(minizinc_xpress minizinc_core ${XPRESS_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) add_dependencies(minizinc_xpress minizinc_parser) ### Setup correct compilation into the MiniZinc library target_compile_definitions(mzn PRIVATE HAS_XPRESS) target_sources(mzn PRIVATE $) target_link_libraries(mzn ${XPRESS_LIBRARIES}) endif() libminizinc-2.4.2/cmake/targets/libmzn.cmake000066400000000000000000000100741360574160400210640ustar00rootroot00000000000000### MiniZinc Library Target # Combined definition of the MiniZinc core and all solvers compiled include(cmake/targets/libminizinc_parser.cmake) include(cmake/targets/libminizinc_fzn.cmake) include(cmake/targets/libminizinc_nl.cmake) add_library(mzn lib/MIPdomains.cpp lib/ast.cpp lib/astexception.cpp lib/aststring.cpp lib/astvec.cpp lib/builtins.cpp lib/cdecode.c lib/cencode.c lib/chain_compressor.cpp lib/copy.cpp lib/eval_par.cpp lib/file_utils.cpp lib/flatten.cpp lib/flatten/flat_exp.cpp lib/flatten/flatten_anon.cpp lib/flatten/flatten_arrayaccess.cpp lib/flatten/flatten_arraylit.cpp lib/flatten/flatten_binop.cpp lib/flatten/flatten_call.cpp lib/flatten/flatten_comp.cpp lib/flatten/flatten_id.cpp lib/flatten/flatten_ite.cpp lib/flatten/flatten_let.cpp lib/flatten/flatten_par.cpp lib/flatten/flatten_setlit.cpp lib/flatten/flatten_unop.cpp lib/flatten/flatten_vardecl.cpp lib/flattener.cpp lib/gc.cpp lib/htmlprinter.cpp lib/json_parser.cpp lib/lexer.lxx lib/miniz.c lib/model.cpp lib/optimize.cpp lib/optimize_constraints.cpp lib/options.cpp lib/output.cpp lib/parser.cpp lib/parser.yxx lib/passes/compile_pass.cpp lib/pathfileprinter.cpp lib/prettyprinter.cpp lib/process.cpp lib/solns2out.cpp lib/solver.cpp lib/solver_config.cpp lib/solver_instance.cpp lib/solver_instance_base.cpp lib/statistics.cpp lib/type.cpp lib/typecheck.cpp lib/values.cpp include/minizinc/ast.hh include/minizinc/ast.hpp include/minizinc/astexception.hh include/minizinc/astiterator.hh include/minizinc/aststring.hh include/minizinc/astvec.hh include/minizinc/builtins.hh include/minizinc/chain_compressor.hh include/minizinc/config.hh.in include/minizinc/copy.hh include/minizinc/eval_par.hh include/minizinc/exception.hh include/minizinc/file_utils.hh include/minizinc/flat_exp.hh include/minizinc/flatten.hh include/minizinc/flatten_internal.hh include/minizinc/flattener.hh include/minizinc/gc.hh include/minizinc/hash.hh include/minizinc/htmlprinter.hh include/minizinc/iter.hh include/minizinc/json_parser.hh include/minizinc/model.hh include/minizinc/optimize.hh include/minizinc/optimize_constraints.hh include/minizinc/options.hh include/minizinc/output.hh include/minizinc/parser.hh include/minizinc/passes/compile_pass.hh include/minizinc/pathfileprinter.hh include/minizinc/prettyprinter.hh include/minizinc/process.hh include/minizinc/solns2out.hh include/minizinc/solver.hh include/minizinc/solver_config.hh include/minizinc/solver_instance.hh include/minizinc/solver_instance_base.hh include/minizinc/statistics.hh include/minizinc/support/regex.hh include/minizinc/thirdparty/b64/cdecode.h include/minizinc/thirdparty/b64/cencode.h include/minizinc/thirdparty/b64/decode.h include/minizinc/thirdparty/b64/encode.h include/minizinc/thirdparty/miniz.h include/minizinc/timer.hh include/minizinc/type.hh include/minizinc/typecheck.hh include/minizinc/utils.hh include/minizinc/values.hh $ $ $ ) target_link_libraries(mzn ${CMAKE_THREAD_LIBS_INIT}) ### Add Solver Interfaces to the MiniZinc library when available include(cmake/targets/libminizinc_cplex.cmake) include(cmake/targets/libminizinc_geas.cmake) include(cmake/targets/libminizinc_gecode.cmake) include(cmake/targets/libminizinc_gurobi.cmake) include(cmake/targets/libminizinc_osicbc.cmake) include(cmake/targets/libminizinc_scip.cmake) include(cmake/targets/libminizinc_xpress.cmake) if(GECODE_FOUND AND USE_GECODE) target_link_libraries(mzn Gecode::Minimodel Gecode::Support) endif() ### Add all necessary files to the install target install( TARGETS mzn EXPORT libminizincTargets RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib ) install( DIRECTORY share/minizinc DESTINATION share ) install( DIRECTORY include/minizinc DESTINATION include PATTERN config.hh.in EXCLUDE ) install( DIRECTORY lib/cached/minizinc DESTINATION include ) libminizinc-2.4.2/cmake/targets/minizinc.cmake000066400000000000000000000003641360574160400214120ustar00rootroot00000000000000#### MiniZinc Executable Target add_executable(minizinc minizinc.cpp) target_link_libraries(minizinc mzn) install( TARGETS minizinc EXPORT libminizincTargets RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib ) libminizinc-2.4.2/cmake/targets/mzn2doc.cmake000066400000000000000000000004071360574160400211440ustar00rootroot00000000000000#### Binary target for MiniZinc documentation generator add_executable(mzn2doc mzn2doc.cpp) target_link_libraries(mzn2doc mzn) install( TARGETS mzn2doc EXPORT libminizincTargets RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib ) libminizinc-2.4.2/cmake/templates/000077500000000000000000000000001360574160400171125ustar00rootroot00000000000000libminizinc-2.4.2/cmake/templates/launch-c.in000066400000000000000000000001321360574160400211300ustar00rootroot00000000000000#!/bin/sh export CCACHE_CPP2=true exec "${RULE_LAUNCH_COMPILE}" "${CMAKE_C_COMPILER}" "$@"libminizinc-2.4.2/cmake/templates/launch-cxx.in000066400000000000000000000001341360574160400215120ustar00rootroot00000000000000#!/bin/sh export CCACHE_CPP2=true exec "${RULE_LAUNCH_COMPILE}" "${CMAKE_CXX_COMPILER}" "$@"libminizinc-2.4.2/cmake/templates/libminizincConfig.cmake.in000066400000000000000000000012341360574160400241560ustar00rootroot00000000000000# - Config file for the libminizinc package # It defines the following variables # libminizinc_INCLUDE_DIRS - include directories for libminizinc # libminizinc_LIBRARIES - libraries to link against # libminizinc_EXECUTABLE - the bar executable # Compute paths get_filename_component(libminizinc_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) set(libminizinc_INCLUDE_DIRS "@CONF_INCLUDE_DIRS@") # Our library dependencies list(APPEND CMAKE_MODULE_PATH ${libminizinc_CMAKE_DIR}) include(CMakeFindDependencyMacro) @CONF_DEPENDENCIES@ # Our library targets (contains definitions for IMPORTED targets) include("${libminizinc_CMAKE_DIR}/libminizincTargets.cmake") libminizinc-2.4.2/cmake/templates/libminizincConfigVersion.cmake.in000066400000000000000000000006001360574160400255200ustar00rootroot00000000000000set(PACKAGE_VERSION "@libminizinc_VERSION@") # Check whether the requested PACKAGE_FIND_VERSION is compatible if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") set(PACKAGE_VERSION_COMPATIBLE FALSE) else() set(PACKAGE_VERSION_COMPATIBLE TRUE) if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") set(PACKAGE_VERSION_EXACT TRUE) endif() endif() libminizinc-2.4.2/include/000077500000000000000000000000001360574160400154575ustar00rootroot00000000000000libminizinc-2.4.2/include/minizinc/000077500000000000000000000000001360574160400172775ustar00rootroot00000000000000libminizinc-2.4.2/include/minizinc/MIPdomains.hh000066400000000000000000000031261360574160400216220ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_mipDOMAINS_HH__ #define __MINIZINC_mipDOMAINS_HH__ #include #include #include #include #include #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #undef ERROR // MICROsoft. #undef min #undef max #endif #define MZN_MIPD__assert_soft( c, e ) \ do { static int nn=0; \ if ( !(c) ) if ( ++nn<=1 ) std::cerr << e << std::endl; } while (0) #define MZN_MIPD__assert_hard( c ) MZN_ASSERT_HARD( c ) #define MZN_MIPD__assert_hard_msg( c, e ) MZN_ASSERT_HARD_MSG( c, e ) #define MZN_MIPD__FLATTENING_ERROR__IF_NOT( cond, envi, loc, msg ) do { if ( !(cond) ) { \ std::ostringstream oss; \ oss << msg; \ throw FlatteningError(envi, loc, oss.str()); \ } } while(0) #define MZN_MIPD__ASSERT_FOR_SAT( cond, envi, loc, msg ) do { if ( !(cond) ) { \ std::ostringstream oss; \ oss << "from MIPDomains: " << msg; \ throw ModelInconsistent(envi, loc, oss.str()); \ } } while(0) //( c, e ) \ // do { if ( !(c) ) { std::ostringstream oss; oss << e; throw MIPD_Infeasibility_Exception(oss.str()); } } while (0) namespace MiniZinc { /// Linearize domain constraints in \a env void MIPdomains(Env& env, bool fVerbose = false, int=0, double=3.0); } #endif libminizinc-2.4.2/include/minizinc/algorithms/000077500000000000000000000000001360574160400214505ustar00rootroot00000000000000libminizinc-2.4.2/include/minizinc/algorithms/min_cut.h000066400000000000000000000007431360574160400232630ustar00rootroot00000000000000#ifndef __MIN_CUT_H #define __MIN_CUT_H #include #include namespace Algorithms { /// An interface to some min-cut algorithm for undirected graphs class MinCut { public: /// INPUT int nNodes=0; std::vector< std::pair< int, int > > edges; std::vector< double > weights; /// OUTPUT std::vector< bool > parities; double wMinCut=1e100; /// Invocation void solve(); }; } // namespace Algorithms #endif // __MIN_CUT_H libminizinc-2.4.2/include/minizinc/ast.hh000066400000000000000000001710551360574160400204200ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_AST_HH__ #define __MINIZINC_AST_HH__ #include #include #include #include #include #include #include #include #include #include #include namespace MiniZinc { class IntLit; class FloatLit; class SetLit; class BoolLit; class StringLit; class Id; class AnonVar; class ArrayLit; class ArrayAccess; class Comprehension; class ITE; class BinOp; class UnOp; class Call; class VarDecl; class Let; class TypeInst; class Item; class FunctionI; class ExpressionSet; class ExpressionSetIter; /// %Location of an expression used during parsing class ParserLocation { protected: /// Source code file name ASTString _filename; /// Line where expression starts unsigned int _first_line; /// Line where expression ends unsigned int _last_line; /// Column where expression starts unsigned int _first_column; /// Column where expression ends unsigned int _last_column; public: /// Construct empty location ParserLocation(void) : _first_line(1), _last_line(1), _first_column(0), _last_column(0) {} /// Construct location ParserLocation(const ASTString& filename, unsigned int first_line, unsigned int first_column, unsigned int last_line, unsigned int last_column) : _filename(filename), _first_line(first_line), _last_line(last_line), _first_column(first_column), _last_column(last_column) {} ASTString filename(void) const { return _filename; } void filename(const ASTString& f) { _filename = f; } unsigned int first_line(void) const { return _first_line; } void first_line(unsigned int l) { _first_line = l; } unsigned int last_line(void) const { return _last_line; } void last_line(unsigned int l) { _last_line = l; } unsigned int first_column(void) const { return _first_column; } void first_column(unsigned int c) { _first_column = c; } unsigned int last_column(void) const { return _last_column; } void last_column(unsigned int c) { _last_column = c; } std::string toString(void) const { std::ostringstream oss; oss << _filename << ":" << _first_line << "." << _first_column; if (_first_line != _last_line) { oss << "-" << _last_line << "." << _last_column; } else if (_first_column != _last_column) { oss << "-" << _last_column; } return oss.str(); } }; /// %Location of an expression in the source code class Location { protected: /// Internal representation of a Location /// Layout depends on sizeof pointer and arguments /// 32 bit pointers: /// Layout 1: filename (32 bit), first line (8 bit), last line-first line (7 bit), first column (6 bit), last column (7 bit) /// Layout 2: filename (32 bit), 4 IntLit for the lines/columns /// 64 bit pointers: /// Layout 1: filename (64 bit), first line (20 bit), last line-first line (20 bit), first column (10 bit), last column (10 bit) /// Layout 2: filename (64 bit), 4 IntLit for the lines/columns class LocVec : public ASTVec { protected: LocVec(const ASTString& filename, unsigned int first_line, unsigned int first_column, unsigned int last_line, unsigned int last_column); LocVec(const ASTString& filename, IntVal combined); public: static LocVec* a(const ASTString& filename, unsigned int first_line, unsigned int first_column, unsigned int last_line, unsigned int last_column); void mark(void) { _gc_mark = 1; if (_data[0]) static_cast(_data[0])->mark(); } ASTString filename(void) const; unsigned int first_line(void) const; unsigned int last_line(void) const; unsigned int first_column(void) const; unsigned int last_column(void) const; }; union LI { LocVec* lv; ptrdiff_t t; } _loc_info; LocVec* lv(void) const { LI li = _loc_info; li.t &= ~static_cast(1); return li.lv; } public: /// Construct empty location Location(void) { _loc_info.lv = NULL; } /// Construct location Location(const ASTString& filename, unsigned int first_line, unsigned int first_column, unsigned int last_line, unsigned int last_column) { if (last_line < first_line) throw InternalError("invalid location"); _loc_info.lv = LocVec::a(filename,first_line,first_column,last_line,last_column); } Location(const ParserLocation& loc) { _loc_info.lv = LocVec::a(loc.filename(),loc.first_line(),loc.first_column(),loc.last_line(),loc.last_column()); } /// Return string representation std::string toString(void) const; /// Return filename ASTString filename(void) const { return lv() ? lv()->filename() : ASTString(); } /// Return first line number unsigned int first_line(void) const { return lv() ? lv()->first_line() : 0; } /// Return last line number unsigned int last_line(void) const { return lv() ? lv()->last_line() : 0; } /// Return first column number unsigned int first_column(void) const { return lv() ? lv()->first_column() : 0; } /// Return last column number unsigned int last_column(void) const { return lv() ? lv()->last_column() : 0; } /// Return whether location is introduced by the compiler bool is_introduced(void) const { return _loc_info.lv==NULL || ( (_loc_info.t & 1) != 0); } /// Mark as alive for garbage collection void mark(void) const; /// Return location with introduced flag set Location introduce(void) const; /// Location used for un-allocated expressions static Location nonalloc; ParserLocation parserLocation(void) const { return ParserLocation(filename(), first_line(), first_column(), last_line(), last_column()); } }; /// Output operator for locations template std::basic_ostream& operator <<(std::basic_ostream& os, const Location& loc) { std::basic_ostringstream s; s.copyfmt(os); s.width(0); if (loc.filename()=="") { s << "unknown file"; } else { s << loc.filename(); } s << ":" << loc.first_line() << "." << loc.first_column(); if (loc.first_line() != loc.last_line()) { s << "-" << loc.last_line() << "." << loc.last_column(); } else if (loc.first_column() != loc.last_column()) { s << "-" << loc.last_column(); } return os << s.str(); } /** * \brief Annotations */ class Annotation { private: ExpressionSet* _s; /// Delete Annotation(const Annotation&); /// Delete Annotation& operator =(const Annotation&); public: Annotation(void) : _s(NULL) {} ~Annotation(void); bool contains(Expression* e) const; bool containsCall(const ASTString& id) const; bool isEmpty(void) const; ExpressionSetIter begin(void) const; ExpressionSetIter end(void) const; void add(Expression* e); void add(std::vector e); void remove(Expression* e); void removeCall(const ASTString& id); void clear(void); void merge(const Annotation& ann); Call* getCall(const ASTString& id) const; static Annotation empty; }; /// returns the Annotation specified by the string; returns NULL if not exists Expression* getAnnotation(const Annotation& ann, std::string str); /// returns the Annotation specified by the string; returns NULL if not exists Expression* getAnnotation(const Annotation& ann, const ASTString& str); /** * \brief Base class for expressions */ class Expression : public ASTNode { protected: /// The %MiniZinc type of the expression Type _type; /// The annotations Annotation _ann; /// The location of the expression Location _loc; /// The hash value of the expression size_t _hash; public: /// Identifier of the concrete expression type enum ExpressionId { E_INTLIT = ASTNode::NID_END+1, E_FLOATLIT, E_SETLIT, E_BOOLLIT, E_STRINGLIT, E_ID, E_ANON, E_ARRAYLIT, E_ARRAYACCESS, E_COMP, E_ITE, E_BINOP, E_UNOP, E_CALL, E_VARDECL, E_LET, E_TI, E_TIID, EID_END = E_TIID }; bool isUnboxedVal(void) const { if (sizeof(double) <= sizeof(FloatLit*)) { // bit 1 or bit 0 is set return (reinterpret_cast(this) & static_cast(3)) != 0; } else { // bit 0 is set return (reinterpret_cast(this) & static_cast(1)) != 0; } } bool isUnboxedInt(void) const { if (sizeof(double) <= sizeof(FloatLit*)) { // bit 1 is set, bit 0 is not set return (reinterpret_cast(this) & static_cast(3)) == 2; } else { // bit 0 is set return (reinterpret_cast(this) & static_cast(1)) == 1; } } bool isUnboxedFloatVal(void) const { // bit 0 is set (and doubles fit inside pointers) return (sizeof(double) <= sizeof(FloatLit*)) && (reinterpret_cast(this) & static_cast(1)) == 1; } ExpressionId eid(void) const { return isUnboxedInt() ? E_INTLIT : isUnboxedFloatVal() ? E_FLOATLIT : static_cast(_id); } const Location& loc(void) const { return isUnboxedVal() ? Location::nonalloc : _loc; } void loc(const Location& l) { if (!isUnboxedVal()) _loc = l; } const Type& type(void) const { return isUnboxedInt() ? Type::unboxedint : isUnboxedFloatVal() ? Type::unboxedfloat : _type; } void type(const Type& t); size_t hash(void) const { return isUnboxedInt() ? unboxedIntToIntVal().hash() : isUnboxedFloatVal() ? unboxedFloatToFloatVal().hash() : _hash; } protected: /// Combination function for hash values void cmb_hash(size_t h) { _hash ^= h + 0x9e3779b9 + (_hash << 6) + (_hash >> 2); } /// Combination function for hash values size_t cmb_hash(size_t seed, size_t h) { seed ^= h + 0x9e3779b9 + (seed << 6) + (seed >> 2); return seed; } /// Compute base hash value void init_hash(void) { _hash = cmb_hash(0,_id); } /// Check if \a e0 and \a e1 are equal static bool equal_internal(const Expression* e0, const Expression* e1); /// Constructor Expression(const Location& loc, const ExpressionId& eid, const Type& t) : ASTNode(eid), _type(t), _loc(loc) {} public: IntVal unboxedIntToIntVal(void) const { assert(isUnboxedInt()); if (sizeof(double) <= sizeof(FloatVal*)) { unsigned long long int i = reinterpret_cast(this) & ~static_cast(7); bool pos = ((reinterpret_cast(this) & static_cast(4)) == 0); if (pos) { return i >> 3; } else { return -(static_cast(i>>3)); } } else { unsigned long long int i = reinterpret_cast(this) & ~static_cast(3); bool pos = ((reinterpret_cast(this) & static_cast(2)) == 0); if (pos) { return i >> 2; } else { return -(static_cast(i>>2)); } } } static IntLit* intToUnboxedInt(long long int i) { static const unsigned int pointerBits = sizeof(IntLit*)*8; if (sizeof(double) <= sizeof(FloatVal*)) { static const long long int maxUnboxedVal = (static_cast(1) << (pointerBits - 3)) - static_cast(1); if (i < -maxUnboxedVal || i > maxUnboxedVal) return NULL; long long int j = i < 0 ? -i : i; ptrdiff_t ubi_p = (static_cast(j) << 3) | static_cast(2); if (i < 0) ubi_p = ubi_p | static_cast(4); return reinterpret_cast(ubi_p); } else { static const long long int maxUnboxedVal = (static_cast(1) << (pointerBits - 2)) - static_cast(1); if (i < -maxUnboxedVal || i > maxUnboxedVal) return NULL; long long int j = i < 0 ? -i : i; ptrdiff_t ubi_p = (static_cast(j) << 2) | static_cast(1); if (i < 0) ubi_p = ubi_p | static_cast(2); return reinterpret_cast(ubi_p); } } FloatVal unboxedFloatToFloatVal(void) const { assert(isUnboxedFloatVal()); union { double d; uint64_t bits; const Expression* p; } _u; _u.p = this; _u.bits = _u.bits >> 1; uint64_t exponent = (_u.bits & (static_cast(0x3FF) << 52)) >> 52; if (exponent != 0) { exponent += 512; // reconstruct original bias of 1023 } uint64_t sign = (_u.bits & (static_cast(1)<<62) ? 1 : 0); _u.bits = (sign << 63) | (exponent << 52) | ( _u.bits & static_cast(0xFFFFFFFFFFFFF)); return _u.d; } static FloatLit* doubleToUnboxedFloatVal(double d) { if (sizeof(double) > sizeof(FloatLit*)) return NULL; union { double d; uint64_t bits; FloatLit* p; } _u; _u.d = d; uint64_t exponent = (_u.bits & (static_cast(0x7FF) << 52)) >> 52; if (exponent != 0) { if (exponent < 513 || exponent > 1534) return NULL; // exponent doesn't fit in 10 bits exponent -= 512; // make exponent fit in 10 bits, with bias 511 } bool sign = (_u.bits & (static_cast(1) << 63)) != 0; _u.bits = _u.bits & ~(static_cast(0x7FF) << 52); // mask out top 11 bits (previously exponent) _u.bits = (_u.bits << 1) | 1u; // shift by one bit and add tag for double _u.bits = _u.bits | (static_cast(sign) << 63) | (static_cast(exponent) << 53); return _u.p; } bool isTagged(void) const { // only bit 2 is set if (isUnboxedVal()) return false; if (sizeof(double) <= sizeof(FloatVal*)) return (reinterpret_cast(this) & static_cast(7)) == 4; else return (reinterpret_cast(this) & static_cast(3)) == 2; } Expression* tag(void) const { assert(!isUnboxedVal()); if (sizeof(double) <= sizeof(FloatVal*)) return reinterpret_cast(reinterpret_cast(this) | static_cast(4)); else return reinterpret_cast(reinterpret_cast(this) | static_cast(2)); } Expression* untag(void) { if (isUnboxedVal()) return this; if (sizeof(double) <= sizeof(FloatVal*)) return reinterpret_cast(reinterpret_cast(this) & ~static_cast(4)); else return reinterpret_cast(reinterpret_cast(this) & ~static_cast(2)); } /// Test if expression is of type \a T template bool isa(void) const { #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wtautological-undefined-compare" #endif if (nullptr==this) throw InternalError("isa: nullptr"); #ifdef __clang__ #pragma clang diagnostic pop #endif return isUnboxedInt() ? T::eid==E_INTLIT : isUnboxedFloatVal() ? T::eid==E_FLOATLIT : _id==T::eid; } /// Cast expression to type \a T* template T* cast(void) { assert(isa()); return static_cast(this); } /// Cast expression to type \a const T* template const T* cast(void) const { assert(isa()); return static_cast(this); } /// Cast expression to type \a T* or NULL if types do not match template T* dyn_cast(void) { return isa() ? static_cast(this) : NULL; } /// Cast expression to type \a const T* or NULL if types do not match template const T* dyn_cast(void) const { return isa() ? static_cast(this) : NULL; } /// Cast expression to type \a T* template static T* cast(Expression* e) { return e==NULL ? NULL : e->cast(); } /// Cast expression to type \a const T* template static const T* cast(const Expression* e) { return e==NULL ? NULL : e->cast(); } /// Cast expression to type \a T* or NULL if types do not match template static T* dyn_cast(Expression* e) { return e==NULL ? NULL : e->dyn_cast(); } /// Cast expression to type \a const T* or NULL if types do not match template static const T* dyn_cast(const Expression* e) { return e==NULL ? NULL : e->dyn_cast(); } /// Add annotation \a ann to the expression void addAnnotation(Expression* ann); /// Add annotation \a ann to the expression void addAnnotations(std::vector ann); const Annotation& ann(void) const { return isUnboxedVal() ? Annotation::empty : _ann; } Annotation& ann(void) { return isUnboxedVal() ? Annotation::empty : _ann; } /// Return hash value of \a e static size_t hash(const Expression* e) { return e==NULL ? 0 : e->hash(); } /// Check if \a e0 and \a e1 are equal static bool equal(const Expression* e0, const Expression* e1); /// Mark \a e as alive for garbage collection static void mark(Expression* e); }; /// \brief Integer literal expression class IntLit : public Expression { protected: /// The value of this expression IntVal _v; /// Constructor IntLit(const Location& loc, IntVal v); public: /// The identifier of this expression type static const ExpressionId eid = E_INTLIT; /// Access value IntVal v(void) const { return isUnboxedInt() ? unboxedIntToIntVal() : _v; } /// Recompute hash value void rehash(void); /// Allocate literal static IntLit* a(IntVal v); /// Allocate literal for enumerated type (only used internally for generators) static IntLit* aEnum(IntVal v, unsigned int enumId); }; /// \brief Float literal expression class FloatLit : public Expression { protected: /// The value of this expression FloatVal _v; /// Constructor FloatLit(const Location& loc, FloatVal v); public: /// The identifier of this expression type static const ExpressionId eid = E_FLOATLIT; /// Access value FloatVal v(void) const { return isUnboxedFloatVal() ? unboxedFloatToFloatVal() : _v; } /// Recompute hash value void rehash(void); /// Allocate literal static FloatLit* a(FloatVal v); }; /// \brief Set literal expression class SetLit : public Expression { protected: /// The value of this expression ASTExprVec _v; union { /// A range-list based representation for an integer set, or NULL IntSetVal* isv; /// A range-list based representation for an float set, or NULL FloatSetVal* fsv; } _u; public: /// The identifier of this expression type static const ExpressionId eid = E_SETLIT; /// Construct set \$f\{v1,\dots,vn\}\$f SetLit(const Location& loc, const std::vector& v); /// Construct set \$f\{v1,\dots,vn\}\$f SetLit(const Location& loc, ASTExprVec v); /// Construct set SetLit(const Location& loc, IntSetVal* isv); /// Construct set SetLit(const Location& loc, FloatSetVal* fsv); /// Access value ASTExprVec v(void) const { return _v; } /// Set value void v(const ASTExprVec& val) { _v = val; } /// Access integer set value if present IntSetVal* isv(void) const { return type().bt()==Type::BT_INT ? _u.isv : NULL; } /// Set integer set value void isv(IntSetVal* val) { _u.isv = val; } /// Access float set value if present FloatSetVal* fsv(void) const { return type().bt()==Type::BT_FLOAT ? _u.fsv : NULL; } /// Set integer set value void fsv(FloatSetVal* val) { _u.fsv = val; } /// Recompute hash value void rehash(void); }; /// \brief Boolean literal expression class BoolLit : public Expression { protected: /// The value of this expression bool _v; public: /// The identifier of this expression type static const ExpressionId eid = E_BOOLLIT; /// Constructor BoolLit(const Location& loc, bool v); /// Access value bool v(void) const { return _v; } /// Recompute hash value void rehash(void); }; /// \brief String literal expression class StringLit : public Expression { protected: /// The value of this expression ASTString _v; public: /// The identifier of this expression type static const ExpressionId eid = E_STRINGLIT; /// Constructor StringLit(const Location& loc, const std::string& v); /// Constructor StringLit(const Location& loc, const ASTString& v); /// Access value ASTString v(void) const { return _v; } /// Set value void v(const ASTString& val) { _v = val; } /// Recompute hash value void rehash(void); }; /// \brief Identifier expression class Id : public Expression { protected: /// The string identifier void* _v_or_idn; /// The declaration corresponding to this identifier (may be NULL) Expression* _decl; public: /// The identifier of this expression type static const ExpressionId eid = E_ID; /// Constructor (\a decl may be NULL) Id(const Location& loc, const std::string& v, VarDecl* decl); /// Constructor (\a decl may be NULL) Id(const Location& loc, const ASTString& v, VarDecl* decl); /// Constructor (\a decl may be NULL) Id(const Location& loc, long long int idn, VarDecl* decl); /// Access identifier ASTString v(void) const; /// Set identifier void v(const ASTString& val) { _v_or_idn = val.aststr(); } /// Access identifier number long long int idn(void) const; /// Set identifier number void idn(long long int n) { _v_or_idn = reinterpret_cast((static_cast(n) << 1) | static_cast(1)); rehash(); } /// Return identifier or X_INTRODUCED plus identifier number ASTString str(void) const; /// Access declaration VarDecl* decl(void) const { Expression* d = _decl; while (d && d->isa()) d = d->cast()->_decl; return Expression::cast(d); } /// Set declaration void decl(VarDecl* d); /// Redirect to another Id \a id void redirect(Id* id) { assert(_decl==NULL || _decl->isa()); _decl = id; } /// Recompute hash value void rehash(void); }; /// \brief Type-inst identifier expression class TIId : public Expression { protected: /// The string identifier ASTString _v; public: /// The identifier of this expression type static const ExpressionId eid = E_TIID; /// Constructor TIId(const Location& loc, const std::string& v); /// Access identifier ASTString v(void) const { return _v; } /// Set identifier void v(const ASTString& val) { _v = val; } /// Check whether it is an enum identifier (starting with two $ signs) bool isEnum(void) const { return _v.c_str()[0]=='$'; } /// Recompute hash value void rehash(void); }; /// \brief Anonymous variable expression class AnonVar : public Expression { public: /// The identifier of this expression type static const ExpressionId eid = E_ANON; /// Constructor AnonVar(const Location& loc); /// Recompute hash value void rehash(void); }; /// \brief Array literal expression class ArrayLit : public Expression { friend class Expression; protected: /// The array union { /// An expression vector (if _flag_2==false) ASTExprVecO* _v; /// Another array literal (if _flag_2==true) ArrayLit* _al; } _u; /// The declared array dimensions // If _flag_2 is true, then this is an array view. In that case, // the _dims array holds the sliced dimensions ASTIntVec _dims; /// Set compressed vector (initial repetitions are removed) void compress(const std::vector& v, const std::vector& dims); public: /// Index conversion from slice to original int origIdx(int i) const; /// Get element \a i of a sliced array Expression* slice_get(int i) const; /// Set element \a i of a sliced array void slice_set(int i, Expression* e); public: /// The identifier of this expression type static const ExpressionId eid = E_ARRAYLIT; /// Constructor ArrayLit(const Location& loc, const std::vector& v, const std::vector >& dims); /// Constructor (existing content) ArrayLit(const Location& loc, ArrayLit& v, const std::vector >& dims); /// Constructor (one-dimensional, existing content) ArrayLit(const Location& loc, ArrayLit& v); /// Constructor (one-dimensional) ArrayLit(const Location& loc, const std::vector& v); /// Constructor (two-dimensional) ArrayLit(const Location& loc, const std::vector >& v); /// Constructor for slices ArrayLit(const Location& loc, ArrayLit* v, const std::vector >& dims, const std::vector >& slice); /// Constructor (one-dimensional) ArrayLit(const Location& loc, const std::vector& v); /// Recompute hash value void rehash(void); // The following methods are only used for copying /// Access value ASTExprVec getVec(void) const { assert(!_flag_2); return _u._v; } /// Set value void setVec(const ASTExprVec& val) { assert(!_flag_2); _u._v = val.vec(); } /// Get underlying array (if this is an array slice) or NULL ArrayLit* getSliceLiteral(void) const { return _flag_2 ? _u._al : NULL; } /// Get underlying _dims vector ASTIntVec dimsInternal(void) const { return _dims; } /// Return number of dimensions int dims(void) const; /// Return minimum index of dimension \a i int min(int i) const; /// Return maximum index of dimension \a i int max(int i) const; /// Return the length of the array int length(void) const; /// Turn into 1d array (only used at the end of flattening) void make1d(void); /// Check if this array was produced by flattening bool flat(void) const { return _flag_1; } /// Set whether this array was produced by flattening void flat(bool b) { _flag_1 = b; } /// Return size of underlying array unsigned int size(void) const { return (_flag_2 || _u._v->flag()) ? length() : _u._v->size(); } /// Access element \a i Expression* operator[](int i) const { return (_flag_2 || _u._v->flag()) ? slice_get(i) : (*_u._v)[i]; } /// Set element \a i void set(int i, Expression* e) { if (_flag_2 || _u._v->flag()) { slice_set(i,e); } else { (*_u._v)[i] = e; } } }; /// \brief Array access expression class ArrayAccess : public Expression { protected: /// The array to access Expression* _v; /// The indexes (for all array dimensions) ASTExprVec _idx; public: /// The identifier of this expression type static const ExpressionId eid = E_ARRAYACCESS; /// Constructor ArrayAccess(const Location& loc, Expression* v, const std::vector& idx); /// Constructor ArrayAccess(const Location& loc, Expression* v, ASTExprVec idx); /// Access value Expression* v(void) const { return _v; } /// Set value void v(Expression* val) { _v = val; } /// Access index sets ASTExprVec idx(void) const { return _idx; } /// Set index sets void idx(const ASTExprVec& idx) { _idx = idx; } /// Recompute hash value void rehash(void); }; /** * \brief Generators for comprehensions * * A generator consists of a list of variable declarations, one for * each generated variable, and the expression to generate. E.g., * the Zinc expression [ x[i,j,k] | i,j in 1..10, k in 1..5] contains * two generators. The first one has variable declarations for i and j * and the expression 1..10, and the second one has a variable declaration * for k and the expression 1..5. * */ class Generator { friend class Comprehension; protected: /// Variable declarations std::vector _v; /// in-expression Expression* _in; /// where-expression Expression* _where; public: /// Allocate Generator(const std::vector& v, Expression* in, Expression* where); /// Allocate Generator(const std::vector& v, Expression* in, Expression* where); /// Allocate Generator(const std::vector& v, Expression* in, Expression* where); /// Allocate Generator(const std::vector& v, Expression* in, Expression* where); /// Allocate single where clause (without generator) at position \a pos Generator(int pos, Expression* where); }; /// \brief A list of generators with one where-expression struct Generators { /// %Generators std::vector _g; /// Constructor Generators(void) {} }; /// \brief An expression representing an array- or set-comprehension class Comprehension : public Expression { friend class Expression; protected: /// The expression to generate Expression* _e; /// A list of generator expressions ASTExprVec _g; /// A list of indices where generators start ASTIntVec _g_idx; public: /// The identifier of this expression type static const ExpressionId eid = E_COMP; /// Constructor Comprehension(const Location& loc, Expression* e, Generators& g, bool set); /// Recompute hash value void rehash(void); /// Whether comprehension is a set bool set(void) const; /// Return number of generators int n_generators(void) const; /// Return "in" expression for generator \a i Expression* in(int i); /// Return "in" expression for generator \a i const Expression* in(int i) const; /// Return number of declarations for generator \a i int n_decls(int i) const; /// Return declaration \a i for generator \a gen VarDecl* decl(int gen, int i); /// Return declaration \a i for generator \a gen const VarDecl* decl(int gen, int i) const; /// Return where clause for generator \a i Expression* where(int i); /// Return where clause for generator \a i const Expression* where(int i) const; /// Return generator body Expression* e(void) const { return _e; } /// Set generator body void e(Expression* e0) { _e = e0; } /// Re-construct (used for copying) void init(Expression* e, Generators& g); /// Check if \a e contains one of the variables bound by this comprehension bool containsBoundVariable(Expression* e); }; /// \brief If-then-else expression class ITE : public Expression { friend class Expression; protected: /// List of if-then-pairs ASTExprVec _e_if_then; /// Else-expression Expression* _e_else; public: /// The identifier of this expression type static const ExpressionId eid = E_ITE; /// Constructor ITE(const Location& loc, const std::vector& e_if_then, Expression* e_else); int size(void) const { return _e_if_then.size()/2; } Expression* e_if(int i) { return _e_if_then[2*i]; } Expression* e_then(int i) { return _e_if_then[2*i+1]; } Expression* e_else(void) { return _e_else; } const Expression* e_if(int i) const { return _e_if_then[2*i]; } const Expression* e_then(int i) const { return _e_if_then[2*i+1]; } const Expression* e_else(void) const { return _e_else; } void e_then(int i, Expression* e) { _e_if_then[2*i+1] = e; } void e_else(Expression* e) { _e_else = e; } /// Recompute hash value void rehash(void); /// Re-construct (used for copying) void init(const std::vector& e_if_then, Expression* e_else); }; /// Type of binary operators enum BinOpType { BOT_PLUS, BOT_MINUS, BOT_MULT, BOT_DIV, BOT_IDIV, BOT_MOD, BOT_POW, BOT_LE, BOT_LQ, BOT_GR, BOT_GQ, BOT_EQ, BOT_NQ, BOT_IN, BOT_SUBSET, BOT_SUPERSET, BOT_UNION, BOT_DIFF, BOT_SYMDIFF, BOT_INTERSECT, BOT_PLUSPLUS, BOT_EQUIV, BOT_IMPL, BOT_RIMPL, BOT_OR, BOT_AND, BOT_XOR, BOT_DOTDOT }; /// \brief Binary-operator expression class BinOp : public Expression { protected: /// Left hand side expression Expression* _e0; /// Right hand side expression Expression* _e1; /// The predicate or function declaration (or NULL) FunctionI* _decl; public: /// The identifier of this expression type static const ExpressionId eid = E_BINOP; /// Constructor BinOp(const Location& loc, Expression* e0, BinOpType op, Expression* e1); /// Access left hand side Expression* lhs(void) const { return _e0; } /// Set left hand side void lhs(Expression* e) { _e0 = e; } /// Access right hand side Expression* rhs(void) const { return _e1; } /// Set right hand side void rhs(Expression* e) { _e1 = e; } /// Access argument \a i Expression* arg(int i) { assert(i==0 || i==1); return i==0 ? _e0 : _e1; } /// Return number of arguments unsigned int n_args(void) const { return 2; } /// Access declaration FunctionI* decl(void) const { return _decl; } /// Set declaration void decl(FunctionI* f) { _decl = f; } /// Return string representation of the operator ASTString opToString(void) const; /// Recompute hash value void rehash(void); /// Return operator type BinOpType op(void) const; /// Morph into a call Call* morph(const ASTString& ident, const std::vector& args); }; /// Type of unary operators enum UnOpType { UOT_NOT, UOT_PLUS, UOT_MINUS }; /// \brief Unary-operator expressions class UnOp : public Expression { protected: /// %Expression Expression* _e0; /// The predicate or function declaration (or NULL) FunctionI* _decl; public: /// The identifier of this expression type static const ExpressionId eid = E_UNOP; /// Constructor UnOp(const Location& loc, UnOpType op, Expression* e); /// Access expression Expression* e(void) const { return _e0; } /// Set expression void e(Expression* e0) { _e0 = e0; } /// Access argument \a i Expression* arg(int i) { assert(i==0); return _e0; } /// Return number of arguments unsigned int n_args(void) const { return 1; } /// Access declaration FunctionI* decl(void) const { return _decl; } /// Set declaration void decl(FunctionI* f) { _decl = f; } ASTString opToString(void) const; /// Recompute hash value void rehash(void); /// Return operator type UnOpType op(void) const; }; /// \brief A predicate or function call expression class Call : public Expression { friend class Expression; protected: union { /// Identifier of called predicate or function ASTStringO* _id; /// The predicate or function declaration (or NULL) FunctionI* _decl; } _u_id; union { /// Single-argument call (tagged pointer) Expression* _oneArg; /// Arguments to the call ASTExprVecO* _args; } _u; /// Check if _u_id contains an id or a decl bool hasId(void) const; public: /// The identifier of this expression type static const ExpressionId eid = E_CALL; /// Constructor Call(const Location& loc, const std::string& id, const std::vector& args); /// Constructor Call(const Location& loc, const ASTString& id, const std::vector& args); /// Access identifier ASTString id(void) const; /// Set identifier (overwrites decl) void id(const ASTString& i); /// Number of arguments unsigned int n_args(void) const { return _u._oneArg->isUnboxedVal() || _u._oneArg->isTagged() ? 1 : _u._args->size(); } /// Access argument \a i Expression* arg(int i) const { assert(i < n_args()); if (_u._oneArg->isUnboxedVal() || _u._oneArg->isTagged()) { assert(i==0); return _u._oneArg->isUnboxedVal() ? _u._oneArg : _u._oneArg->untag(); } else { return (*_u._args)[i]; } } /// Set argument \a i void arg(int i, Expression* e) { assert(i < n_args()); if (_u._oneArg->isUnboxedVal() || _u._oneArg->isTagged()) { assert(i==0); _u._oneArg = e->isUnboxedVal() ? e : e->tag(); } else { (*_u._args)[i] = e; } } /// Set arguments void args(const ASTExprVec& a) { if (a.size()==1) { _u._oneArg = a[0]->isUnboxedVal() ? a[0] : a[0]->tag(); } else { _u._args = a.vec(); assert(!_u._oneArg->isTagged()); } } /// Access declaration FunctionI* decl(void) const; /// Set declaration (overwrites id) void decl(FunctionI* f); /// Recompute hash value void rehash(void); }; /// \brief A variable declaration expression class VarDecl : public Expression { protected: /// Type-inst of the declared variable TypeInst* _ti; /// Identifier Id* _id; /// Initialisation expression (can be NULL) Expression* _e; /// Flattened version of the VarDecl WeakRef _flat; /// Integer payload int _payload; public: /// The identifier of this expression type static const ExpressionId eid = E_VARDECL; /// Constructor VarDecl(const Location& loc, TypeInst* ti, const std::string& id, Expression* e=NULL); /// Constructor VarDecl(const Location& loc, TypeInst* ti, const ASTString& id, Expression* e=NULL); /// Constructor VarDecl(const Location& loc, TypeInst* ti, long long int idn, Expression* e=NULL); /// Constructor VarDecl(const Location& loc, TypeInst* ti, Id* id, Expression* e=NULL); /// Access TypeInst TypeInst* ti(void) const { return _ti; } /// Set TypeInst void ti(TypeInst* t) { _ti=t; } /// Access identifier Id* id(void) const { return _id; } /// Access initialisation expression Expression* e(void) const; /// Set initialisation expression void e(Expression* rhs); /// Access flattened version VarDecl* flat(void) { return _flat() ? _flat()->cast() : NULL; } /// Set flattened version void flat(VarDecl* vd); /// Recompute hash value void rehash(void); /// Whether variable is toplevel bool toplevel(void) const; /// Whether variable is toplevel void toplevel(bool t); /// Whether variable is introduced bool introduced(void) const; /// Whether variable is introduced void introduced(bool t); /// Whether variable has been evaluated bool evaluated(void) const; /// Whether variable has been evaluated void evaluated(bool t); /// Access payload int payload(void) const { return _payload; } /// Set payload void payload(int i) { _payload = i; } /// Put current value on trail void trail(void); }; class EnvI; class CopyMap; /// \brief %Let expression class Let : public Expression { friend Expression* copy(EnvI& env, CopyMap& m, Expression* e, bool followIds, bool copyFundecls, bool isFlatModel); friend class Expression; protected: /// List of local declarations ASTExprVec _let; /// Copy of original local declarations ASTExprVec _let_orig; /// Body of the let Expression* _in; public: /// The identifier of this expression type static const ExpressionId eid = E_LET; /// Constructor Let(const Location& loc, const std::vector& let, Expression* in); /// Recompute hash value void rehash(void); /// Access local declarations ASTExprVec let(void) const { return _let; } /// Access local declarations ASTExprVec let_orig(void) const { return _let_orig; } /// Access body Expression* in(void) const { return _in; } /// Remember current let bindings void pushbindings(void); /// Restore previous let bindings void popbindings(void); }; /// \brief Type-inst expression class TypeInst : public Expression { protected: /// Ranges of an array expression ASTExprVec _ranges; /// Declared domain (or NULL) Expression* _domain; public: /// The identifier of this expression type static const ExpressionId eid = E_TI; /// Constructor TypeInst(const Location& loc, const Type& t, ASTExprVec ranges, Expression* domain=NULL); /// Constructor TypeInst(const Location& loc, const Type& t, Expression* domain=NULL); /// Access ranges ASTExprVec ranges(void) const { return _ranges; } /// Access domain Expression* domain(void) const { return _domain; } //// Set domain void domain(Expression* d) { _domain = d; } /// Set ranges to \a ranges void setRanges(const std::vector& ranges); bool isarray(void) const { return _ranges.size()>0; } bool hasTiVariable(void) const; /// Recompute hash value void rehash(void); /// Check if domain is computed from right hand side of variable bool computedDomain(void) const { return _flag_1; } /// Set if domain is computed from right hand side of variable void setComputedDomain(bool b) { _flag_1=b; } /// Check if this TypeInst represents an enum bool isEnum(void) const { return _flag_2; } /// Set if this TypeInst represents an enum void setIsEnum(bool b) { _flag_2=b; } }; /** * \brief Base-class for items */ class Item : public ASTNode { protected: /// Location of the item Location _loc; public: /// Identifier of the concrete item type enum ItemId { II_INC = Expression::EID_END+1, II_VD, II_ASN, II_CON, II_SOL, II_OUT, II_FUN, II_END = II_FUN }; ItemId iid(void) const { return static_cast(_id); } const Location& loc(void) const { return _loc; } protected: /// Constructor Item(const Location& loc, const ItemId& iid) : ASTNode(iid), _loc(loc) { _flag_1 = false; } public: /// Test if item is of type \a T template bool isa(void) const { return _id==T::iid; } /// Cast item to type \a T* template T* cast(void) { assert(isa()); return static_cast(this); } /// Cast expression to type \a const T* template const T* cast(void) const { assert(isa()); return static_cast(this); } /// Cast item to type \a T* or NULL if types do not match template T* dyn_cast(void) { return isa() ? static_cast(this) : NULL; } /// Cast item to type \a const T* or NULL if types do not match template const T* dyn_cast(void) const { return isa() ? static_cast(this) : NULL; } /// Cast item to type \a T* template static T* cast(Item* i) { return i==NULL ? NULL : i->cast(); } /// Cast item to type \a const T* template static const T* cast(const Item* i) { return i==NULL ? NULL : i->cast(); } /// Cast item to type \a T* or NULL if types do not match template static T* dyn_cast(Item* i) { return i==NULL ? NULL : i->dyn_cast(); } /// Cast item to type \a const T* or NULL if types do not match template static const T* dyn_cast(const Item* i) { return i==NULL ? NULL : i->dyn_cast(); } /// Check if item should be removed bool removed(void) const { return _flag_1; } /// Set flag to remove item void remove(void) { _flag_1 = true; } /// Unset remove item flag (only possible if not already removed by compact()) void unremove(void) { _flag_1 = false; } }; class Model; /// \brief Include item class IncludeI : public Item { protected: /// Filename to include ASTString _f; /// Model for that file Model* _m; public: /// The identifier of this item type static const ItemId iid = II_INC; /// Constructor IncludeI(const Location& loc, const ASTString& f); /// Access filename ASTString f(void) const { return _f; } /// Set filename void f(const ASTString& nf) { _f = nf; } /// Access model Model* m(void) const { return _m; } /// Set the model void m(Model* m0, bool own=true) { assert(_m==NULL || m0==NULL); _m = m0; _flag_2 = own; } bool own(void) const { return _flag_2; } }; /// \brief Variable declaration item class VarDeclI : public Item { protected: /// The declaration expression VarDecl* _e; public: /// The identifier of this item type static const ItemId iid = II_VD; /// Constructor VarDeclI(const Location& loc, VarDecl* e); /// Access expression VarDecl* e(void) const { return _e; } /// Set expression void e(VarDecl* vd) { _e = vd; } /// Flag used during compilation bool flag(void) const { return _flag_2; } /// Set flag used during compilation void flag(bool b) { _flag_2 = b; } }; /// \brief Assign item class AssignI : public Item { protected: /// Identifier of variable to assign to ASTString _id; /// Expression to assign to the variable Expression* _e; /// Declaration of the variable to assign to VarDecl* _decl; public: /// The identifier of this item type static const ItemId iid = II_ASN; /// Constructor AssignI(const Location& loc, const std::string& id, Expression* e); /// Access identifier ASTString id(void) const { return _id; } /// Access expression Expression* e(void) const { return _e; } /// Set expression void e(Expression* e0) { _e = e0; } /// Access declaration VarDecl* decl(void) const { return _decl; } /// Set declaration void decl(VarDecl* d) { _decl = d; } }; /// \brief Constraint item class ConstraintI : public Item { protected: /// Constraint expression Expression* _e; public: /// The identifier of this item type static const ItemId iid = II_CON; /// Constructor ConstraintI(const Location& loc, Expression* e); /// Access expression Expression* e(void) const { return _e; } /// Set expression void e(Expression* e0) { _e = e0; } /// Flag used during compilation bool flag(void) const { return _flag_2; } /// Set flag used during compilation void flag(bool b) { _flag_2 = b; } }; /// \brief Solve item class SolveI : public Item { protected: /// Solve item annotation Annotation _ann; /// Expression for minimisation/maximisation (or NULL) Expression* _e; /// Constructor SolveI(const Location& loc, Expression* e); public: /// The identifier of this item type static const ItemId iid = II_SOL; /// Type of solving enum SolveType { ST_SAT, ST_MIN, ST_MAX }; /// Allocate solve satisfy item static SolveI* sat(const Location& loc); /// Allocate solve minimize item static SolveI* min(const Location& loc, Expression* e); /// Allocate solve maximize item static SolveI* max(const Location& loc, Expression* e); /// Access solve annotation const Annotation& ann(void) const { return _ann; } /// Access solve annotation Annotation& ann(void) { return _ann; } /// Access expression for optimisation Expression* e(void) const { return _e; } /// Set expression for optimisation void e(Expression* e0) { _e=e0; } /// Return type of solving SolveType st(void) const; /// Set type of solving void st(SolveType s); }; /// \brief Output item class OutputI : public Item { protected: /// Expression to output Expression* _e; public: /// The identifier of this item type static const ItemId iid = II_OUT; /// Constructor OutputI(const Location& loc, Expression* e); /// Access expression Expression* e(void) const { return _e; } /// Update expression void e(Expression* e) { _e=e; } }; class EnvI; /// \brief Function declaration item class FunctionI : public Item { protected: /// Identifier of this function ASTString _id; /// Type-inst of the return value TypeInst* _ti; /// List of parameter declarations ASTExprVec _params; /// Annotation Annotation _ann; /// Function body (or NULL) Expression* _e; /// Whether function is defined in the standard library bool _from_stdlib; public: /// The identifier of this item type static const ItemId iid = II_FUN; /// Type of builtin expression-valued functions typedef Expression* (*builtin_e) (EnvI&, Call*); /// Type of builtin int-valued functions typedef IntVal (*builtin_i) (EnvI&, Call*); /// Type of builtin bool-valued functions typedef bool (*builtin_b) (EnvI&, Call*); /// Type of builtin float-valued functions typedef FloatVal (*builtin_f) (EnvI&, Call*); /// Type of builtin set-valued functions typedef IntSetVal* (*builtin_s) (EnvI&, Call*); /// Type of builtin string-valued functions typedef std::string (*builtin_str) (EnvI&, Call*); /// Builtin functions (or NULL) struct { builtin_e e; builtin_i i; builtin_f f; builtin_b b; builtin_s s; builtin_str str; } _builtins; /// Constructor FunctionI(const Location& loc, const std::string& id, TypeInst* ti, const std::vector& params, Expression* e = NULL); /// Constructor FunctionI(const Location& loc, const ASTString& id, TypeInst* ti, const ASTExprVec& params, Expression* e = NULL); /// Access identifier ASTString id(void) const { return _id; } /// Access TypeInst TypeInst* ti(void) const { return _ti; } /// Access parameters ASTExprVec params(void) const { return _params; } /// Access annotation const Annotation& ann(void) const { return _ann; } /// Access annotation Annotation& ann(void) { return _ann; } /// Access body Expression* e(void) const { return _e; } /// Set body void e(Expression* b) { _e = b; } /** \brief Compute return type given argument types \a ta */ Type rtype(EnvI& env, const std::vector& ta, bool strictEnums); /** \brief Compute return type given argument types \a ta */ Type rtype(EnvI& env, const std::vector& ta, bool strictEnums); /** \brief Compute expected type of argument \a n given argument types \a ta */ Type argtype(EnvI& env, const std::vector& ta, int n); /// Return whether function is defined in the standard library bool from_stdlib(void) const { return _from_stdlib; }; /// Mark for GC void mark(void) { _gc_mark = 1; loc().mark(); } }; /** * \brief Visitor for expressions * * This class implements no-ops for all expression types. * Override the methods to implement custom behaviour. */ class EVisitor { public: /// Visit integer literal void vIntLit(const IntLit&) {} /// Visit floating point literal void vFloatLit(const FloatLit&) {} /// Visit Boolean literal void vBoolLit(const BoolLit&) {} /// Visit set literal void vSetLit(const SetLit&) {} /// Visit string literal void vStringLit(const StringLit&) {} /// Visit identifier void vId(const Id&) {} /// Visit anonymous variable void vAnonVar(const AnonVar&) {} /// Visit array literal void vArrayLit(const ArrayLit&) {} /// Visit array access void vArrayAccess(const ArrayAccess&) {} /// Visit array comprehension void vComprehension(const Comprehension&) {} /// Visit array comprehension (only generator \a gen_i) void vComprehensionGenerator(const Comprehension&, int gen_i) { (void) gen_i; } /// Visit if-then-else void vITE(const ITE&) {} /// Visit binary operator void vBinOp(const BinOp&) {} /// Visit unary operator void vUnOp(const UnOp&) {} /// Visit call void vCall(const Call&) {} /// Visit let void vLet(const Let&) {} /// Visit variable declaration void vVarDecl(const VarDecl&) {} /// Visit type inst void vTypeInst(const TypeInst&) {} /// Visit TIId void vTIId(const TIId&) {} /// Determine whether to enter node bool enter(Expression* e) { return true; } /// Exit node after processing has finished void exit(Expression* e) {} }; /// Statically allocated constants class Constants { private: /// Garbage collection root set for constants Model* m; public: /// Literal true BoolLit* lit_true; /// Variable bound to true VarDecl* var_true; /// Literal false BoolLit* lit_false; /// Variable bound to false VarDecl* var_false; /// Special variable to signal compiler to ignore result VarDecl* var_ignore; /// Infinite set SetLit* infinity; /// Function item used to keep track of redefined variables FunctionI* var_redef; /// Literal absent value Expression* absent; /// Identifiers for builtins struct { ASTString forall; ASTString forall_reif; ASTString exists; ASTString clause; ASTString bool2int; ASTString int2float; ASTString bool2float; ASTString assert; ASTString mzn_deprecate; ASTString trace; ASTString sum; ASTString lin_exp; ASTString element; ASTString show; ASTString fix; ASTString output; struct { ASTString lin_eq; ASTString lin_le; ASTString lin_ne; ASTString plus; ASTString minus; ASTString times; ASTString div; ASTString mod; ASTString lt; ASTString le; ASTString gt; ASTString ge; ASTString eq; ASTString ne; } int_; struct { ASTString lin_eq; ASTString lin_le; ASTString lin_ne; ASTString plus; ASTString minus; ASTString times; ASTString div; ASTString mod; ASTString lt; ASTString le; ASTString gt; ASTString ge; ASTString eq; ASTString ne; } int_reif; struct { ASTString lin_eq; ASTString lin_le; ASTString lin_lt; ASTString lin_ne; ASTString plus; ASTString minus; ASTString times; ASTString div; ASTString mod; ASTString lt; ASTString le; ASTString gt; ASTString ge; ASTString eq; ASTString ne; ASTString in; ASTString dom; } float_; struct { ASTString lin_eq; ASTString lin_le; ASTString lin_lt; ASTString lin_ne; ASTString plus; ASTString minus; ASTString times; ASTString div; ASTString mod; ASTString lt; ASTString le; ASTString gt; ASTString ge; ASTString eq; ASTString ne; ASTString in; } float_reif; ASTString bool_eq; ASTString bool_eq_reif; ASTString array_bool_or; ASTString array_bool_and; ASTString bool_clause; ASTString bool_clause_reif; ASTString bool_xor; ASTString set_eq; ASTString set_in; ASTString set_card; ASTString pow; ASTString introduced_var; ASTString anonEnumFromStrings; } ids; /// Identifiers for Boolean contexts struct { Id* root; Id* pos; Id* neg; Id* mix; } ctx; /// Common annotations struct { Id* output_var; ASTString output_array; Id* add_to_output; Id* output_only; Id* mzn_check_var; ASTString mzn_check_enum_var; Id* is_defined_var; ASTString defines_var; Id* is_reverse_map; Id* promise_total; Id* maybe_partial; ASTString doc_comment; ASTString mzn_path; ASTString is_introduced; Id* user_cut; // MIP Id* lazy_constraint; // MIP Id* mzn_break_here; Id* rhs_from_assignment; Id* domain_change_constraint; ASTString mzn_deprecated; } ann; /// Command line options struct { /// basic MiniZinc command line options ASTString cmdlineData_str; ASTString cmdlineData_short_str; ASTString datafile_str; ASTString datafile_short_str; ASTString globalsDir_str; ASTString globalsDir_alt_str; ASTString globalsDir_short_str; ASTString help_str; ASTString help_short_str; ASTString ignoreStdlib_str; ASTString include_str; ASTString inputFromStdin_str; ASTString instanceCheckOnly_str; ASTString no_optimize_str; ASTString no_optimize_alt_str; ASTString no_outputOzn_str; ASTString no_outputOzn_short_str; ASTString no_typecheck_str; ASTString newfzn_str; ASTString outputBase_str; ASTString outputFznToStdout_str; ASTString outputFznToStdout_alt_str; ASTString outputOznToFile_str; ASTString outputOznToStdout_str; ASTString outputFznToFile_str; ASTString outputFznToFile_alt_str; ASTString outputFznToFile_short_str; ASTString rangeDomainsOnly_str; ASTString statistics_str; ASTString statistics_short_str; ASTString stdlib_str; ASTString verbose_str; ASTString verbose_short_str; ASTString version_str; ASTString werror_str; struct { ASTString all_sols_str; ASTString fzn_solver_str; } solver; } cli; /// options strings to find setting in Options map struct { ASTString cmdlineData; ASTString datafile; ASTString datafiles; ASTString fznToStdout; ASTString fznToFile; ASTString globalsDir; ASTString ignoreStdlib; ASTString includeDir; ASTString includePaths; ASTString instanceCheckOnly; ASTString inputFromStdin; ASTString model; ASTString newfzn; ASTString noOznOutput; ASTString optimize; ASTString outputBase; ASTString oznToFile; ASTString oznToStdout; ASTString rangeDomainsOnly; ASTString statistics; ASTString stdlib; ASTString typecheck; ASTString verbose; ASTString werror; struct { ASTString allSols; ASTString numSols; ASTString threads; ASTString fzn_solver; ASTString fzn_flags; ASTString fzn_flag; ASTString fzn_time_limit_ms; ASTString fzn_sigint; } solver; } opts; /// categories of the command line interface options struct { ASTString general; ASTString io; ASTString solver; ASTString translation; } cli_cat; /// Keep track of allocated integer literals std::unordered_map integerMap; /// Keep track of allocated float literals std::unordered_map floatMap; /// Constructor Constants(void); /// Return shared BoolLit BoolLit* boollit(bool b) { return b ? lit_true : lit_false; } static const int max_array_size = std::numeric_limits::max() / 2; }; /// Return static instance Constants& constants(void); } #include #endif libminizinc-2.4.2/include/minizinc/ast.hpp000066400000000000000000000524241360574160400206060ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ namespace MiniZinc { inline bool Expression::equal(const Expression* e0, const Expression* e1) { if (e0==e1) return true; if (e0 == NULL || e1 == NULL) return false; if (e0->isUnboxedInt() || e1->isUnboxedInt()) return false; if (e0->isUnboxedFloatVal() || e1->isUnboxedFloatVal()) { if (e0->isUnboxedFloatVal() && e1->isUnboxedFloatVal()) { return e0->unboxedFloatToFloatVal()==e1->unboxedFloatToFloatVal(); } return false; } if (e0->_id != e1->_id) return false; if (e0->type() != e1->type()) return false; if (e0->hash() != e1->hash()) return false; return equal_internal(e0, e1); } inline void Expression::type(const Type& t) { if (isUnboxedVal()) { assert(!isUnboxedInt() || t == Type::parint()); assert(!isUnboxedFloatVal() || t == Type::parfloat()); return; } if (eid()==E_VARDECL) { this->cast()->id()->_type = t; } else if (eid()==E_ID && this->cast()->decl()) { assert(_type.bt() == Type::BT_UNKNOWN || _type.dim()==t.dim() || t.dim() != -1); this->cast()->decl()->_type = t; } _type = t; } inline IntLit::IntLit(const Location& loc, IntVal v) : Expression(loc,E_INTLIT,Type::parint()), _v(v) { rehash(); } inline IntLit* IntLit::a(MiniZinc::IntVal v) { if (v.isFinite()) { IntLit* ret = intToUnboxedInt(v.toInt()); if (ret) { return ret; } } std::unordered_map::iterator it = constants().integerMap.find(v); if (it==constants().integerMap.end() || it->second()==NULL) { IntLit* il = new IntLit(Location().introduce(), v); if (it==constants().integerMap.end()) { constants().integerMap.insert(std::make_pair(v, il)); } else { it->second = il; } return il; } else { return it->second()->cast(); } } inline IntLit* IntLit::aEnum(IntVal v, unsigned int enumId) { if (enumId==0) return a(v); IntLit* il = new IntLit(Location().introduce(), v); Type tt(il->type()); tt.enumId(enumId); il->type(tt); return il; } inline ASTString Location::LocVec::filename(void) const { return static_cast(_data[0]); } inline unsigned int Location::LocVec::first_line(void) const { if (_size==2) { static const unsigned int pointerBits = sizeof(IntLit*)*8; IntLit* il = static_cast(_data[1]); long long unsigned int mask = pointerBits<=32 ? 0xFF : 0xFFFFF; union { long long int i; unsigned long long int u; } ui; ui.i = il->v().toInt(); return static_cast(ui.u & mask); } else { IntLit* il = static_cast(_data[1]); return il->v().toInt(); } } inline unsigned int Location::LocVec::last_line(void) const { if (_size==2) { static const unsigned int pointerBits = sizeof(IntLit*)*8; IntLit* il = static_cast(_data[1]); long long unsigned int first_line_size = pointerBits<=32 ? 8 : 20; long long unsigned int mask = pointerBits<=32 ? 0xFF : 0xFFFFF; long long unsigned int offsetmask = pointerBits<=32 ? 0x7F : 0xFFFFF; union { long long int i; unsigned long long int u; } ui; ui.i = il->v().toInt(); // return first line (8 bit) + offset (7 bit) return static_cast( (ui.u & mask) + ((ui.u >> first_line_size) & offsetmask)); } else { IntLit* il = static_cast(_data[2]); return il->v().toInt(); } } inline unsigned int Location::LocVec::first_column(void) const { if (_size==2) { static const unsigned int pointerBits = sizeof(IntLit*)*8; IntLit* il = static_cast(_data[1]); long long unsigned int first_col_offset = pointerBits<=32 ? 8+7 : 20+20; long long unsigned int mask = pointerBits<=32 ? 0x3F : 0x3FF; union { long long int i; unsigned long long int u; } ui; ui.i = il->v().toInt(); // return first line (8 bit) + offset (7 bit) return static_cast( (ui.u >> first_col_offset) & mask); } else { IntLit* il = static_cast(_data[3]); return il->v().toInt(); } } inline unsigned int Location::LocVec::last_column(void) const { if (_size==2) { static const unsigned int pointerBits = sizeof(IntLit*)*8; IntLit* il = static_cast(_data[1]); long long unsigned int last_col_offset = pointerBits<=32 ? 8+7+6 : 20+20+10; long long unsigned int mask = pointerBits<=32 ? 0x7F : 0x3FF; union { long long int i; unsigned long long int u; } ui; ui.i = il->v().toInt(); // return first line (8 bit) + offset (7 bit) return static_cast( (ui.u >> last_col_offset) & mask); } else { IntLit* il = static_cast(_data[4]); return il->v().toInt(); } } inline FloatLit::FloatLit(const Location& loc, FloatVal v) : Expression(loc,E_FLOATLIT,Type::parfloat()), _v(v) { rehash(); } inline FloatLit* FloatLit::a(MiniZinc::FloatVal v) { if (sizeof(double) <= sizeof(FloatLit*) && v.isFinite()) { FloatLit* ret = Expression::doubleToUnboxedFloatVal(v.toDouble()); if (ret) { return ret; } } std::unordered_map::iterator it = constants().floatMap.find(v); if (it==constants().floatMap.end() || it->second()==NULL) { FloatLit* fl = new FloatLit(Location().introduce(), v); if (it==constants().floatMap.end()) { constants().floatMap.insert(std::make_pair(v, fl)); } else { it->second = fl; } return fl; } else { return it->second()->cast(); } } inline SetLit::SetLit(const Location& loc, const std::vector& v) : Expression(loc,E_SETLIT,Type()), _v(ASTExprVec(v)) { _u.isv = NULL; rehash(); } inline SetLit::SetLit(const Location& loc, ASTExprVec v) : Expression(loc,E_SETLIT,Type()), _v(v) { _u.isv = NULL; rehash(); } inline SetLit::SetLit(const Location& loc, IntSetVal* isv) : Expression(loc,E_SETLIT,Type()) { _type = Type::parsetint(); _u.isv = isv; rehash(); } inline SetLit::SetLit(const Location& loc, FloatSetVal* fsv) : Expression(loc,E_SETLIT,Type()) { _type = Type::parsetfloat(); _u.fsv = fsv; rehash(); } inline BoolLit::BoolLit(const Location& loc, bool v) : Expression(loc,E_BOOLLIT,Type::parbool()), _v(v) { rehash(); } inline StringLit::StringLit(const Location& loc, const std::string& v) : Expression(loc,E_STRINGLIT,Type::parstring()), _v(ASTString(v)) { rehash(); } inline StringLit::StringLit(const Location& loc, const ASTString& v) : Expression(loc,E_STRINGLIT,Type::parstring()), _v(v) { rehash(); } inline Id::Id(const Location& loc, const std::string& v0, VarDecl* decl) : Expression(loc,E_ID,Type()), _decl(decl) { v(v0); rehash(); } inline Id::Id(const Location& loc, const ASTString& v0, VarDecl* decl) : Expression(loc,E_ID,Type()), _decl(decl) { v(v0); rehash(); } inline Id::Id(const Location& loc, long long int idn0, VarDecl* decl) : Expression(loc,E_ID,Type()), _decl(decl) { idn(idn0); rehash(); } inline void Id::decl(VarDecl* d) { _decl = d; } inline ASTString Id::v(void) const { if (_decl && _decl->isa()) { Expression* d = _decl; while (d && d->isa()) { d = d->cast()->_decl; } return d->cast()->id()->v(); } else { assert((reinterpret_cast(_v_or_idn) & static_cast(1)) == 0); return ASTString(reinterpret_cast(_v_or_idn)); } } inline long long int Id::idn(void) const { if (_decl && _decl->isa()) { Expression* d = _decl; while (d && d->isa()) { d = d->cast()->_decl; } return d->cast()->id()->idn(); } else { if ((reinterpret_cast(_v_or_idn) & static_cast(1)) == 0) return -1; long long int i = reinterpret_cast(_v_or_idn) & ~static_cast(1); return i >> 1; } } inline TIId::TIId(const Location& loc, const std::string& v) : Expression(loc,E_TIID,Type()), _v(ASTString(v)) { rehash(); } inline AnonVar::AnonVar(const Location& loc) : Expression(loc,E_ANON,Type()) { rehash(); } inline ArrayLit::ArrayLit(const Location& loc, ArrayLit& v, const std::vector >& dims) : Expression(loc,E_ARRAYLIT,Type()) { _flag_1 = false; _flag_2 = v._flag_2; if (_flag_2) { _u._al = v._u._al; std::vector d(dims.size()*2+v._dims.size()-v.dims()*2); for (unsigned int i=static_cast(dims.size()); i--;) { d[i*2] = dims[i].first; d[i*2+1] = dims[i].second; } int sliceOffset = static_cast(dims.size())*2; int origSliceOffset = v.dims()*2; for (int i=0; i<_u._al->dims()*2; i++) { d[sliceOffset+i] = v._dims[origSliceOffset+i]; } _dims = ASTIntVec(d); } else { std::vector d(dims.size()*2); for (unsigned int i=static_cast(dims.size()); i--;) { d[i*2] = dims[i].first; d[i*2+1] = dims[i].second; } if (v._u._v->flag() || d.size()!=2 || d[0]!=1) { // only allocate dims vector if it is not a 1d array indexed from 1 _dims = ASTIntVec(d); } _u._v = v._u._v; } rehash(); } inline ArrayLit::ArrayLit(const Location& loc, ArrayLit& v) : Expression(loc,E_ARRAYLIT,Type()) { _flag_1 = false; _flag_2 = v._flag_2; if (_flag_2) { _u._al = v._u._al; std::vector d(2+v._dims.size()-v.dims()*2); d[0] = 1; d[1] = v.size(); int sliceOffset = 2; int origSliceOffset = v.dims()*2; for (int i=0; i<_u._al->dims()*2; i++) { d[sliceOffset+i] = v._dims[origSliceOffset+i]; } _dims = ASTIntVec(d); } else { _u._v = v._u._v; if (_u._v->flag()) { std::vector d(2); d[0] = 1; d[1] = v.length(); _dims = ASTIntVec(d); } else { // don't allocate dims vector since this is a 1d array indexed from 1 } } rehash(); } inline ArrayLit::ArrayLit(const Location& loc, const std::vector& v) : Expression(loc,E_ARRAYLIT,Type()) { _flag_1 = false; _flag_2 = false; std::vector d(2); d[0] = 1; d[1] = static_cast(v.size()); compress(v, d); rehash(); } inline ArrayLit::ArrayLit(const Location& loc, const std::vector& v) : Expression(loc,E_ARRAYLIT,Type()) { _flag_1 = false; _flag_2 = false; std::vector d(2); d[0] = 1; d[1] = static_cast(v.size()); std::vector vv(v.size()); for (unsigned int i=0; i >& v) : Expression(loc,E_ARRAYLIT,Type()) { _flag_1 = false; _flag_2 = false; std::vector dims(4); dims[0]=1; dims[1]=static_cast(v.size()); dims[2]=1; dims[3]=v.size() > 0 ? static_cast(v[0].size()) : 0; std::vector vv; for (unsigned int i=0; i& idx) : Expression(loc,E_ARRAYACCESS,Type()) { _v = v; _idx = ASTExprVec(idx); rehash(); } inline ArrayAccess::ArrayAccess(const Location& loc, Expression* v, ASTExprVec idx) : Expression(loc,E_ARRAYACCESS,Type()) { _v = v; _idx = idx; rehash(); } inline void Comprehension::init(Expression *e, Generators &g) { _e = e; std::vector es; std::vector idx; for (unsigned int i=0; i(es.size())); es.push_back(g._g[i]._in); es.push_back(g._g[i]._where); for (unsigned int j=0; j(es.size())); _g = ASTExprVec(es); _g_idx = ASTIntVec(idx); rehash(); } inline Comprehension::Comprehension(const Location& loc, Expression* e, Generators& g, bool set) : Expression(loc,E_COMP,Type()) { _flag_1 = set; init(e,g); } inline void ITE::init(const std::vector& e_if_then, Expression* e_else) { _e_if_then = ASTExprVec(e_if_then); _e_else = e_else; rehash(); } inline ITE::ITE(const Location& loc, const std::vector& e_if_then, Expression* e_else) : Expression(loc,E_ITE,Type()) { init(e_if_then,e_else); } inline BinOp::BinOp(const Location& loc, Expression* e0, BinOpType op, Expression* e1) : Expression(loc,E_BINOP,Type()), _e0(e0), _e1(e1), _decl(NULL) { _sec_id = op; rehash(); } inline UnOp::UnOp(const Location& loc, UnOpType op, Expression* e) : Expression(loc,E_UNOP,Type()), _e0(e), _decl(NULL) { _sec_id = op; rehash(); } inline bool Call::hasId(void) const { return (reinterpret_cast(_u_id._decl) & static_cast(1)) == 0; } inline ASTString Call::id(void) const { return hasId() ? _u_id._id : decl()->id(); } inline void Call::id(const ASTString& i) { _u_id._id = i.aststr(); assert(hasId()); assert(decl()==NULL); } inline FunctionI* Call::decl(void) const { return hasId() ? NULL : reinterpret_cast(reinterpret_cast(_u_id._decl) & ~static_cast(1)); } inline void Call::decl(FunctionI* f) { assert(f != NULL); _u_id._decl = reinterpret_cast(reinterpret_cast(f) | static_cast(1)); } inline Call::Call(const Location& loc, const std::string& id0, const std::vector& args) : Expression(loc, E_CALL,Type()) { _flag_1 = false; id(ASTString(id0)); if (args.size()==1) { _u._oneArg = args[0]->isUnboxedVal() ? args[0] : args[0]->tag(); } else { _u._args = ASTExprVec(args).vec(); } rehash(); assert(hasId()); assert(decl() == NULL); } inline Call::Call(const Location& loc, const ASTString& id0, const std::vector& args) : Expression(loc, E_CALL,Type()) { _flag_1 = false; id(ASTString(id0)); if (args.size()==1) { _u._oneArg = args[0]->isUnboxedVal() ? args[0] : args[0]->tag(); } else { _u._args = ASTExprVec(args).vec(); } rehash(); assert(hasId()); assert(decl() == NULL); } inline VarDecl::VarDecl(const Location& loc, TypeInst* ti, const ASTString& id, Expression* e) : Expression(loc,E_VARDECL,ti ? ti->type() : Type()), _id(NULL), _flat(NULL) { _id = new Id(loc,id,this); _flag_1 = true; _flag_2 = false; _ti = ti; _e = e; _id->type(type()); _payload = 0; rehash(); } inline VarDecl::VarDecl(const Location& loc, TypeInst* ti, long long int idn, Expression* e) : Expression(loc,E_VARDECL,ti ? ti->type() : Type()), _id(NULL), _flat(NULL) { _id = new Id(loc,idn,this); _flag_1 = true; _flag_2 = false; _ti = ti; _e = e; _id->type(type()); _payload = 0; rehash(); } inline VarDecl::VarDecl(const Location& loc, TypeInst* ti, const std::string& id, Expression* e) : Expression(loc,E_VARDECL,ti->type()), _id(NULL), _flat(NULL) { _id = new Id(loc,ASTString(id),this); _flag_1 = true; _flag_2 = false; _ti = ti; _e = e; _id->type(type()); _payload = 0; rehash(); } inline VarDecl::VarDecl(const Location& loc, TypeInst* ti, Id* id, Expression* e) : Expression(loc,E_VARDECL,ti->type()), _id(NULL), _flat(NULL) { if (id->idn()==-1) _id = new Id(loc,id->v(),this); else _id = new Id(loc,id->idn(),this); _flag_1 = true; _flag_2 = false; _ti = ti; _e = e; _id->type(type()); _payload = 0; rehash(); } inline Expression* VarDecl::e(void) const { return (_e==nullptr || _e->isUnboxedVal()) ? _e : _e->untag(); } inline void VarDecl::e(Expression* rhs) { assert(rhs==NULL || !rhs->isa() || rhs->cast() != _id); _e = rhs; } inline bool VarDecl::toplevel(void) const { return _flag_1; } inline void VarDecl::toplevel(bool t) { _flag_1 = t; } inline bool VarDecl::introduced(void) const { return _flag_2; } inline void VarDecl::introduced(bool t) { _flag_2 = t; } inline bool VarDecl::evaluated(void) const { return _e->isUnboxedVal() || _e->isTagged(); } inline void VarDecl::evaluated(bool t) { if (!_e->isUnboxedVal()) { if (t) _e = _e->tag(); else _e = _e->untag(); } } inline void VarDecl::flat(VarDecl* vd) { _flat = WeakRef(vd); } inline TypeInst::TypeInst(const Location& loc, const Type& type, ASTExprVec ranges, Expression* domain) : Expression(loc,E_TI,type), _ranges(ranges), _domain(domain) { _flag_1 = false; _flag_2 = false; rehash(); } inline TypeInst::TypeInst(const Location& loc, const Type& type, Expression* domain) : Expression(loc,E_TI,type), _domain(domain) { _flag_1 = false; _flag_2 = false; rehash(); } inline IncludeI::IncludeI(const Location& loc, const ASTString& f) : Item(loc, II_INC), _f(f), _m(NULL) {} inline VarDeclI::VarDeclI(const Location& loc, VarDecl* e) : Item(loc, II_VD), _e(e) {} inline AssignI::AssignI(const Location& loc, const std::string& id, Expression* e) : Item(loc, II_ASN), _id(ASTString(id)), _e(e), _decl(NULL) {} inline ConstraintI::ConstraintI(const Location& loc, Expression* e) : Item(loc, II_CON), _e(e) {} inline SolveI::SolveI(const Location& loc, Expression* e) : Item(loc, II_SOL), _e(e) {} inline SolveI* SolveI::sat(const Location& loc) { SolveI* si = new SolveI(loc,NULL); si->_sec_id = ST_SAT; return si; } inline SolveI* SolveI::min(const Location& loc, Expression* e) { SolveI* si = new SolveI(loc,e); si->_sec_id = ST_MIN; return si; } inline SolveI* SolveI::max(const Location& loc, Expression* e) { SolveI* si = new SolveI(loc,e); si->_sec_id = ST_MAX; return si; } inline SolveI::SolveType SolveI::st(void) const { return static_cast(_sec_id); } inline void SolveI::st(SolveI::SolveType s) { _sec_id = s; } inline OutputI::OutputI(const Location& loc, Expression* e) : Item(loc, II_OUT), _e(e) {} inline FunctionI::FunctionI(const Location& loc, const std::string& id, TypeInst* ti, const std::vector& params, Expression* e) : Item(loc, II_FUN), _id(ASTString(id)), _ti(ti), _params(ASTExprVec(params)), _e(e) { _builtins.e = NULL; _builtins.b = NULL; _builtins.f = NULL; _builtins.i = NULL; _builtins.s = NULL; _builtins.str = NULL; _from_stdlib = (loc.filename() == "builtins.mzn" || loc.filename().endsWith("/builtins.mzn") || loc.filename() == "stdlib.mzn" || loc.filename().endsWith("/stdlib.mzn") || loc.filename() == "flatzinc_builtins.mzn" || loc.filename().endsWith("/flatzinc_builtins.mzn")); } inline FunctionI::FunctionI(const Location& loc, const ASTString& id, TypeInst* ti, const ASTExprVec& params, Expression* e) : Item(loc, II_FUN), _id(id), _ti(ti), _params(params), _e(e) { _builtins.e = NULL; _builtins.b = NULL; _builtins.f = NULL; _builtins.i = NULL; _builtins.s = NULL; _builtins.str = NULL; _from_stdlib = (loc.filename() == "builtins.mzn" || loc.filename().endsWith("/builtins.mzn") || loc.filename() == "stdlib.mzn" || loc.filename().endsWith("/stdlib.mzn") || loc.filename() == "flatzinc_builtins.mzn" || loc.filename().endsWith("/flatzinc_builtins.mzn")); } } libminizinc-2.4.2/include/minizinc/astexception.hh000066400000000000000000000052201360574160400223250ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_ASTEXCEPTION_HH__ #define __MINIZINC_ASTEXCEPTION_HH__ #include #include #include #include namespace MiniZinc { class SyntaxError : public Exception { protected: Location _loc; public: SyntaxError(const Location& loc, const std::string& msg) : Exception(msg), _loc(loc) {} virtual ~SyntaxError(void) throw() {} virtual const char* what(void) const throw() { return "MiniZinc: syntax error"; } const Location& loc(void) const { return _loc; } }; class LocationException : public Exception { protected: Location _loc; public: LocationException(EnvI& env, const Location& loc, const std::string& msg); virtual ~LocationException(void) throw() {} const Location& loc(void) const { return _loc; } }; class TypeError : public LocationException { public: TypeError(EnvI& env, const Location& loc, const std::string& msg) : LocationException(env,loc,msg) {} ~TypeError(void) throw() {} virtual const char* what(void) const throw() { return "MiniZinc: type error"; } }; class EvalError : public LocationException { public: EvalError(EnvI& env, const Location& loc, const std::string& msg) : LocationException(env,loc,msg) {} EvalError(EnvI& env, const Location& loc, const std::string& msg, const ASTString& name) : LocationException(env,loc,msg+" '"+name.str()+"'") {} ~EvalError(void) throw() {} virtual const char* what(void) const throw() { return "MiniZinc: evaluation error"; } }; class ModelInconsistent : public LocationException { public: ModelInconsistent(EnvI& env, const Location& loc, const std::string& msg="") : LocationException(env,loc,"model inconsistency detected" + (msg.empty() ? msg : ": ") + msg) {} ~ModelInconsistent(void) throw() {} virtual const char* what(void) const throw() { return "MiniZinc: warning"; } }; class ResultUndefinedError : public LocationException { public: ResultUndefinedError(EnvI& env, const Location& loc, const std::string& msg); ~ResultUndefinedError(void) throw() {} virtual const char* what(void) const throw() { return "MiniZinc: result of evaluation is undefined"; } }; } #endif libminizinc-2.4.2/include/minizinc/astiterator.hh000066400000000000000000000273651360574160400221760ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_ASTITERATOR_HH__ #define __MINIZINC_ASTITERATOR_HH__ #include #include namespace MiniZinc { /** * \brief Bottom-up iterator for expressions */ template class BottomUpIterator { protected: /// The visitor to call back during iteration T& _t; /// Stack item struct C { /// Expression on the stack Expression* _e; /// Whether this expression has been visited before bool _done; /// If part of a generator expression, which one it is int _gen_i; /// Constructor C(Expression* e) : _e(e), _done(false), _gen_i(-1) {} /// Constructor for generator expression C(Expression* e, int gen_i) : _e(e), _done(true), _gen_i(gen_i) {} }; /// Push all elements of \a v onto \a stack template void pushVec(std::vector& stack, ASTExprVec v) { for (unsigned int i=0; i void bottomUp(T& t, Expression* e) { BottomUpIterator(t).run(e); } /** * \brief Leaf iterator for expressions */ template class TopDownIterator { protected: /// The visitor to call back during iteration T& _t; /// Push all elements of \a v onto \a stack template static void pushVec(std::vector& stack, ASTExprVec v) { for (unsigned int i=0; i void topDown(T& t, Expression* e) { TopDownIterator(t).run(e); } /* IMPLEMENTATION */ template void BottomUpIterator::run(Expression* root) { std::vector stack; if (_t.enter(root)) stack.push_back(C(root)); while (!stack.empty()) { C& c = stack.back(); if (c._e==NULL) { stack.pop_back(); continue; } if (c._done) { switch (c._e->eid()) { case Expression::E_INTLIT: _t.vIntLit(*c._e->template cast()); break; case Expression::E_FLOATLIT: _t.vFloatLit(*c._e->template cast()); break; case Expression::E_SETLIT: _t.vSetLit(*c._e->template cast()); break; case Expression::E_BOOLLIT: _t.vBoolLit(*c._e->template cast()); break; case Expression::E_STRINGLIT: _t.vStringLit(*c._e->template cast()); break; case Expression::E_ID: _t.vId(*c._e->template cast()); break; case Expression::E_ANON: _t.vAnonVar(*c._e->template cast()); break; case Expression::E_ARRAYLIT: _t.vArrayLit(*c._e->template cast()); break; case Expression::E_ARRAYACCESS: _t.vArrayAccess(*c._e->template cast()); break; case Expression::E_COMP: if (c._gen_i >= 0) { _t.vComprehensionGenerator(*c._e->template cast(), c._gen_i); } else { _t.vComprehension(*c._e->template cast()); } break; case Expression::E_ITE: _t.vITE(*c._e->template cast()); break; case Expression::E_BINOP: _t.vBinOp(*c._e->template cast()); break; case Expression::E_UNOP: _t.vUnOp(*c._e->template cast()); break; case Expression::E_CALL: _t.vCall(*c._e->template cast()); break; case Expression::E_VARDECL: _t.vVarDecl(*c._e->template cast()); break; case Expression::E_LET: _t.vLet(*c._e->template cast()); break; case Expression::E_TI: _t.vTypeInst(*c._e->template cast()); break; case Expression::E_TIID: _t.vTIId(*c._e->template cast()); break; } _t.exit(c._e); stack.pop_back(); } else { c._done=true; Expression* ce = c._e; for (ExpressionSetIter it = ce->ann().begin(); it != ce->ann().end(); ++it) { if (_t.enter(*it)) stack.push_back(C(*it)); } if (_t.enter(ce)) { switch (ce->eid()) { case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_BOOLLIT: case Expression::E_STRINGLIT: case Expression::E_ANON: case Expression::E_ID: case Expression::E_TIID: break; case Expression::E_SETLIT: pushVec(stack, ce->template cast()->v()); break; case Expression::E_ARRAYLIT: { for (unsigned int i=0; icast()->size(); i++) stack.push_back((*ce->cast())[i]); } break; case Expression::E_ARRAYACCESS: pushVec(stack, ce->template cast()->idx()); stack.push_back(C(ce->template cast()->v())); break; case Expression::E_COMP: { Comprehension* comp = ce->template cast(); stack.push_back(C(comp->e())); for (unsigned int i=comp->n_generators(); i--; ) { for (unsigned int j=comp->n_decls(i); j--; ) { stack.push_back(C(comp->decl(i, j))); } if (comp->in(i)) { stack.push_back(C(comp->where(i))); stack.push_back(C(comp,i)); stack.push_back(C(comp->in(i))); } else { stack.push_back(C(comp,i)); stack.push_back(C(comp->where(i))); } } } break; case Expression::E_ITE: { ITE* ite = ce->template cast(); stack.push_back(C(ite->e_else())); for (int i=0; isize(); i++) { stack.push_back(C(ite->e_if(i))); stack.push_back(C(ite->e_then(i))); } } break; case Expression::E_BINOP: stack.push_back(C(ce->template cast()->rhs())); stack.push_back(C(ce->template cast()->lhs())); break; case Expression::E_UNOP: stack.push_back(C(ce->template cast()->e())); break; case Expression::E_CALL: for (unsigned int i=0; itemplate cast()->n_args(); i++) stack.push_back(ce->template cast()->arg(i)); break; case Expression::E_VARDECL: stack.push_back(C(ce->template cast()->e())); stack.push_back(C(ce->template cast()->ti())); break; case Expression::E_LET: stack.push_back(C(ce->template cast()->in())); pushVec(stack, ce->template cast()->let()); break; case Expression::E_TI: stack.push_back(C(ce->template cast()->domain())); pushVec(stack,ce->template cast()->ranges()); break; } } else { c._e = NULL; } } } } template void TopDownIterator::run(Expression* root) { std::vector stack; if (_t.enter(root)) stack.push_back(root); while (!stack.empty()) { Expression* e = stack.back(); stack.pop_back(); if (e==NULL) { continue; } if (!_t.enter(e)) continue; for (ExpressionSetIter it = e->ann().begin(); it != e->ann().end(); ++it) { stack.push_back(*it); } switch (e->eid()) { case Expression::E_INTLIT: _t.vIntLit(*e->template cast()); break; case Expression::E_FLOATLIT: _t.vFloatLit(*e->template cast()); break; case Expression::E_SETLIT: _t.vSetLit(*e->template cast()); pushVec(stack, e->template cast()->v()); break; case Expression::E_BOOLLIT: _t.vBoolLit(*e->template cast()); break; case Expression::E_STRINGLIT: _t.vStringLit(*e->template cast()); break; case Expression::E_ID: _t.vId(*e->template cast()); break; case Expression::E_ANON: _t.vAnonVar(*e->template cast()); break; case Expression::E_ARRAYLIT: _t.vArrayLit(*e->template cast()); for (unsigned int i=0; icast()->size(); i++) stack.push_back((*e->cast())[i]); break; case Expression::E_ARRAYACCESS: _t.vArrayAccess(*e->template cast()); pushVec(stack, e->template cast()->idx()); stack.push_back(e->template cast()->v()); break; case Expression::E_COMP: _t.vComprehension(*e->template cast()); { Comprehension* comp = e->template cast(); for (unsigned int i=comp->n_generators(); i--; ) { stack.push_back(comp->where(i)); stack.push_back(comp->in(i)); for (unsigned int j=comp->n_decls(i); j--; ) { stack.push_back(comp->decl(i, j)); } } stack.push_back(comp->e()); } break; case Expression::E_ITE: _t.vITE(*e->template cast()); { ITE* ite = e->template cast(); stack.push_back(ite->e_else()); for (int i=0; isize(); i++) { stack.push_back(ite->e_if(i)); stack.push_back(ite->e_then(i)); } } break; case Expression::E_BINOP: _t.vBinOp(*e->template cast()); stack.push_back(e->template cast()->rhs()); stack.push_back(e->template cast()->lhs()); break; case Expression::E_UNOP: _t.vUnOp(*e->template cast()); stack.push_back(e->template cast()->e()); break; case Expression::E_CALL: _t.vCall(*e->template cast()); for (unsigned int i=0; itemplate cast()->n_args(); i++) stack.push_back(e->template cast()->arg(i)); break; case Expression::E_VARDECL: _t.vVarDecl(*e->template cast()); stack.push_back(e->template cast()->e()); stack.push_back(e->template cast()->ti()); break; case Expression::E_LET: _t.vLet(*e->template cast()); stack.push_back(e->template cast()->in()); pushVec(stack, e->template cast()->let()); break; case Expression::E_TI: _t.vTypeInst(*e->template cast()); stack.push_back(e->template cast()->domain()); pushVec(stack,e->template cast()->ranges()); break; case Expression::E_TIID: _t.vTIId(*e->template cast()); break; } } } } #endif libminizinc-2.4.2/include/minizinc/aststring.hh000066400000000000000000000133071360574160400216420ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_ASTSTRING_HH__ #define __MINIZINC_ASTSTRING_HH__ #include #include #include #include #include namespace MiniZinc { class ASTStringO; /** * \brief Handler for ASTStringO objects */ class ASTString { protected: /// String ASTStringO* _s; public: /// Default constructor ASTString(void) : _s(NULL) {} /// Constructor ASTString(ASTStringO* s) : _s(s) {} /// Constructor ASTString(const std::string& s); /// Copy constructor ASTString(const ASTString& s); /// Assignment operator ASTString& operator= (const ASTString& s); /// Size of the string unsigned int size(void) const; /// Underlying C string object const char* c_str(void) const; /// Conversion to STL string std::string str(void) const; /// Underlying string implementation ASTStringO* aststr(void) const { return _s; } /// Return if string is equal to \a s bool operator== (const ASTString& s) const; /// Return if string is not equal to \a s bool operator!= (const ASTString& s) const; /// Return if string is equal to \a s bool operator== (const std::string& s) const; /// Return if string is not equal to \a s bool operator!= (const std::string& s) const; /// Return if string ends with \a s bool endsWith(const std::string& s) const; /// Return if string begins with \a s bool beginsWith(const std::string& s) const; /// Compute hash value of string size_t hash(void) const; /// Mark string during garbage collection void mark(void) const; }; /// Hash map from strings to \a T template struct ASTStringMap { /// The map type specialised for ASTString typedef std::unordered_map t; }; /** * \brief Print integer set \a s * \relates Gecode::IntSet */ template std::basic_ostream& operator <<(std::basic_ostream& os, const ASTString& s) { return s.size()==0 ? os : (os << s.c_str()); } } namespace std { template<> struct hash { public: size_t operator()(const MiniZinc::ASTString& s) const; }; } namespace std { template<> struct equal_to { public: bool operator()(const MiniZinc::ASTString& s0, const MiniZinc::ASTString& s1) const; }; } namespace MiniZinc { /** * \brief Garbage collected string */ class ASTStringO : public ASTChunk { protected: /// Constructor ASTStringO(const std::string& s); public: /// Allocate and initialise as \a s static ASTStringO* a(const std::string& s); /// Return underlying C-style string const char* c_str(void) const { return _data+sizeof(size_t); } /// Conversion to STL string std::string str(void) const { return std::string(c_str()); } /// Return size of string unsigned int size(void) const { return static_cast(_size)-static_cast(sizeof(size_t))-1; } /// Access character at position \a i char operator[](unsigned int i) { assert(i(_data)[0]; } /// Mark for garbage collection void mark(void) const { _gc_mark = 1; } }; inline ASTString::ASTString(const std::string& s) : _s(ASTStringO::a(s)) {} inline ASTString::ASTString(const ASTString& s) : _s(s._s) {} inline ASTString& ASTString::operator= (const ASTString& s) { _s = s._s; return *this; } inline unsigned int ASTString::size(void) const { return _s ? _s->size() : 0; } inline const char* ASTString::c_str(void) const { return _s ? _s->c_str() : NULL; } inline std::string ASTString::str(void) const { return _s ? _s->str() : std::string(""); } inline void ASTString::mark(void) const { if (_s) _s->mark(); } inline bool ASTString::operator== (const ASTString& s) const { return size()==s.size() && (size()==0 || strncmp(_s->c_str(),s._s->c_str(),size())==0); } inline bool ASTString::operator!= (const ASTString& s) const { return !(*this == s); } inline bool ASTString::operator== (const std::string& s) const { return size()==s.size() && (size()==0 || strncmp(_s->c_str(),s.c_str(),size())==0); } inline bool ASTString::operator!= (const std::string& s) const { return !(*this == s); } inline bool ASTString::endsWith(const std::string &s) const { return size() >= s.size() && (size() == 0 || strncmp(_s->c_str()+size()-s.size(), s.c_str(), s.size())==0); } inline bool ASTString::beginsWith(const std::string &s) const { return size() >= s.size() && (size() == 0 || strncmp(_s->c_str(), s.c_str(), s.size())==0); } inline size_t ASTString::hash(void) const { return _s ? _s->hash() : 0; } } namespace std { inline size_t hash::operator()( const MiniZinc::ASTString& s) const { return s.hash(); } } namespace std { inline bool equal_to::operator()(const MiniZinc::ASTString& s0, const MiniZinc::ASTString& s1) const { return s0==s1; } } #endif libminizinc-2.4.2/include/minizinc/astvec.hh000066400000000000000000000144771360574160400211220ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_ASTVEC_HH__ #define __MINIZINC_ASTVEC_HH__ #include #include namespace MiniZinc { class ASTIntVecO; /** * \brief Handler for ASTIntVecO objects */ class ASTIntVec { protected: /// Vector ASTIntVecO* _v; public: /// Default constructor ASTIntVec(void) : _v(NULL) {} /// Constructor ASTIntVec(ASTIntVecO* v) : _v(v) {} /// Constructor ASTIntVec(const std::vector& v); /// Copy constructor ASTIntVec(const ASTIntVec& s); /// Assignment operator ASTIntVec& operator= (const ASTIntVec& s); /// Size of vector unsigned int size(void) const; /// Element access int& operator[](unsigned int i); /// Element access int operator[](unsigned int i) const; /// Iterator begin int* begin(void); /// Iterator end int* end(void); /// Mark as alive for garbage collection void mark(void) const; }; template class ASTExprVecO; /** * \brief Handler for ASTExprVecO objects */ template class ASTExprVec { protected: /// Vector ASTExprVecO* _v; public: /// Default constructor ASTExprVec(void) : _v(NULL) {} /// Constructor ASTExprVec(ASTExprVecO* v) : _v(v) {} /// Constructor ASTExprVec(const std::vector& v); /// Copy constructor ASTExprVec(const ASTExprVec& v); /// Assignment operator ASTExprVec& operator= (const ASTExprVec& v); /// Size of vector unsigned int size(void) const; /// Element access T*& operator[](unsigned int i); /// Element access T* operator[](unsigned int i) const; /// Iterator begin T** begin(void); /// Iterator end T** end(void); /// Return vector object ASTExprVecO* vec(void) const; /// Mark as alive for garbage collection void mark(void) const; }; /// Garbage collected integer vector class ASTIntVecO : public ASTChunk { protected: /// Constructor ASTIntVecO(const std::vector& v); public: /// Allocate and initialise from \a v static ASTIntVecO* a(const std::vector& v); /// Return size unsigned int size(void) const { return static_cast(_size/sizeof(int)); } /// Return element at position \a i int& operator[](unsigned int i) { assert(i(_data)[i]; } /// Return element at position \a i int operator[](unsigned int i) const { assert(i(_data)[i]; } /// Iterator begin int* begin(void) { return reinterpret_cast(_data); } /// Iterator end int* end(void) { return begin()+size(); } /// Mark as alive for garbage collection void mark(void) const { _gc_mark = 1; } }; /// Garbage collected vector of expressions template class ASTExprVecO : public ASTVec { protected: /// Constructor ASTExprVecO(const std::vector& v); public: /// Allocate and initialise from \a v static ASTExprVecO* a(const std::vector& v); unsigned int size(void) const { return static_cast(_size); } bool empty(void) const { return size()==0; } T& operator[] (int i) { assert(i(size())); return reinterpret_cast(_data[i]); } const T operator[] (int i) const { assert(i(size())); return reinterpret_cast(_data[i]); } /// Iterator begin T* begin(void) { return reinterpret_cast(_data); } /// Iterator end T* end(void) { return begin()+size(); } /// Mark as alive for garbage collection void mark(void) const { _gc_mark = 1; } /// Check if flag is set bool flag(void) const { return _flag_1; } /// Set flag void flag(bool f) { _flag_1 = f; } }; template ASTExprVecO::ASTExprVecO(const std::vector& v) : ASTVec(v.size()) { _flag_1 = false; for (unsigned int i=static_cast(v.size()); i--;) (*this)[i] = v[i]; } template ASTExprVecO* ASTExprVecO::a(const std::vector& v) { ASTExprVecO* ao = static_cast*>(alloc(v.size())); new (ao) ASTExprVecO(v); return ao; } inline ASTIntVec::ASTIntVec(const std::vector& v) : _v(ASTIntVecO::a(v)) {} inline ASTIntVec::ASTIntVec(const ASTIntVec& v) : _v(v._v) {} inline ASTIntVec& ASTIntVec::operator= (const ASTIntVec& v) { _v = v._v; return *this; } inline unsigned int ASTIntVec::size(void) const { return _v ? _v->size() : 0; } inline int& ASTIntVec::operator[](unsigned int i) { return (*_v)[i]; } inline int ASTIntVec::operator[](unsigned int i) const { return (*_v)[i]; } inline int* ASTIntVec::begin(void) { return _v ? _v->begin() : NULL; } inline int* ASTIntVec::end(void) { return _v ? _v->end() : NULL; } inline void ASTIntVec::mark(void) const { if (_v) _v->mark(); } template ASTExprVec::ASTExprVec(const std::vector& v) : _v(ASTExprVecO::a(v)) {} template inline ASTExprVec::ASTExprVec(const ASTExprVec& v) : _v(v._v) {} template inline ASTExprVec& ASTExprVec::operator =(const ASTExprVec& v) { _v = v._v; return *this; } template inline unsigned int ASTExprVec::size(void) const { return _v ? _v->size() : 0; } template inline T*& ASTExprVec::operator[](unsigned int i) { return (*_v)[i]; } template inline T* ASTExprVec::operator[](unsigned int i) const { return (*_v)[i]; } template inline T** ASTExprVec::begin(void) { return _v ? _v->begin() : NULL; } template inline T** ASTExprVec::end(void) { return _v ? _v->end() : NULL; } template inline ASTExprVecO* ASTExprVec::vec(void) const { return _v; } template inline void ASTExprVec::mark(void) const { if (_v) _v->mark(); } } #endif libminizinc-2.4.2/include/minizinc/builtins.hh000066400000000000000000000010741360574160400214530ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_BUILTINS_HH__ #define __MINIZINC_BUILTINS_HH__ #include namespace MiniZinc { /// Add builtins to the functions defined in \a env.model() void registerBuiltins(Env& env); } #endif libminizinc-2.4.2/include/minizinc/chain_compressor.hh000066400000000000000000000062111360574160400231560ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Jip J. Dekker */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_CHAIN_COMPRESSOR_H__ #define __MINIZINC_CHAIN_COMPRESSOR_H__ #include #include namespace MiniZinc { class ChainCompressor { public: ChainCompressor(EnvI &env, Model &m, std::vector &deletedVarDecls) : env(env), m(m), deletedVarDecls(deletedVarDecls) {}; virtual bool trackItem(Item *i) = 0; virtual void compress() = 0; protected: EnvI &env; Model &m; std::vector &deletedVarDecls; std::multimap items; typedef std::multimap::iterator iterator; void storeItem(VarDecl *v, Item *i) { items.emplace(v, i); } void updateCount(); unsigned long count(VarDecl *v) { return items.count(v); } std::pair find(VarDecl *v) {return items.equal_range(v);}; void removeItem(Item *i); int addItem(Item *i); // Replaces the Nth argument of a Call c by Expression e, c must be located on Item i void replaceCallArgument(Item *i, Call *c, unsigned int n, Expression *e); }; class ImpCompressor : public ChainCompressor { public: ImpCompressor(EnvI &env, Model &m, std::vector &deletedVarDecls, std::vector &boolConstraints0) : ChainCompressor(env, m, deletedVarDecls), boolConstraints(boolConstraints0) {}; bool trackItem(Item *i) override; void compress() override; protected: std::vector &boolConstraints; // Compress two implications. e.g. (x -> y) /\ (y -> z) => x -> z // In this case i: (y -> z), newLHS: x // Function returns true if compression was successful (and the implication that contains newLHS can be removed) // Side effect: Item i might be removed. bool compressItem(Item *i, VarDecl *newLHS); // Constructs a clause constraint item with pos and neg as parameters. // if pos/neg are not ArrayLit then they will inserted into an ArrayLit. ConstraintI *constructClause(Expression *pos, Expression *neg); ConstraintI *constructHalfReif(Call *call, Id *control); }; class LECompressor : public ChainCompressor { public: LECompressor(EnvI &env, Model &m, std::vector &deletedVarDecls) : ChainCompressor(env, m, deletedVarDecls) {}; bool trackItem(Item *i) override; void compress() override; protected: std::map aliasMap; /// Replace the use a variable within an inequality /// e.g. i: int_lin_le([1,2,3], [a,b,c], 10), oldVar: a, newVar d -> int_lin_le([1,2,3], [d,b,c], 10) /// Occurrence count is updated for variables involved. template void LEReplaceVar(Item *i, VarDecl *oldVar, VarDecl *newVar); /// Check if the bounds of two Variables are equal bool eqBounds(Expression* a, Expression* b); }; } #endif //__MINIZINC_CHAIN_COMPRESSOR_H__ libminizinc-2.4.2/include/minizinc/config.hh.in000066400000000000000000000010401360574160400214650ustar00rootroot00000000000000#define MZN_VERSION_MAJOR "${libminizinc_VERSION_MAJOR}" #define MZN_VERSION_MINOR "${libminizinc_VERSION_MINOR}" #define MZN_VERSION_PATCH "${libminizinc_VERSION_PATCH}" #define MZN_BUILD_REF "${BUILD_REF}" #cmakedefine HAS_DECLSPEC_THREAD #cmakedefine HAS_ATTR_THREAD #cmakedefine HAS_PIDPATH #cmakedefine HAS_GETMODULEFILENAME #cmakedefine HAS_GETFILEATTRIBUTES #cmakedefine HAS_MEMCPY_S #cmakedefine COMPILE_BOOST_MINCUT #cmakedefine HAS_DLFCN_H #cmakedefine HAS_WINDOWS_H #cmakedefine GUROBI_PLUGIN #cmakedefine CPLEX_PLUGIN libminizinc-2.4.2/include/minizinc/copy.hh000066400000000000000000000043551360574160400206010ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_COPY_HH__ #define __MINIZINC_COPY_HH__ #include namespace MiniZinc { class CopyMap { protected: typedef std::unordered_map ModelMap; ModelMap model_m; ASTNodeWeakMap node_m; public: void insert(Expression* e0, Expression* e1); Expression* find(Expression* e); void insert(Item* e0, Item* e1); Item* find(Item* e); void insert(Model* e0, Model* e1); Model* find(Model* e); void insert(const ASTString& e0, const ASTString& e1); ASTStringO* find(const ASTString& e); void insert(IntSetVal* e0, IntSetVal* e1); IntSetVal* find(IntSetVal* e); void insert(FloatSetVal* e0, FloatSetVal* e1); FloatSetVal* find(FloatSetVal* e); template void insert(ASTExprVec e0, ASTExprVec e1) { node_m.insert(e0.vec(),e1.vec()); } template ASTExprVecO* find(ASTExprVec e) { ASTNode* n = node_m.find(e.vec()); return static_cast*>(n); } void clear() { model_m.clear(); node_m.clear(); } }; /// Create a deep copy of expression \a e Expression* copy(EnvI& env, Expression* e, bool followIds=false, bool copyFundecls=false, bool isFlatModel=false); /// Create a deep copy of item \a i Item* copy(EnvI& env, Item* i, bool followIds=false, bool copyFundecls=false, bool isFlatModel=false); /// Create a deep copy of model \a m Model* copy(EnvI& env, Model* m); /// Create a deep copy of expression \a e Expression* copy(EnvI& env, CopyMap& map, Expression* e, bool followIds=false, bool copyFundecls=false, bool isFlatModel=false); /// Create a deep copy of item \a i Item* copy(EnvI& env, CopyMap& map, Item* i, bool followIds=false, bool copyFundecls=false, bool isFlatModel=false); /// Create a deep copy of model \a m Model* copy(EnvI& env, CopyMap& map, Model* m, bool isFlatModel=false); } #endif libminizinc-2.4.2/include/minizinc/eval_par.hh000066400000000000000000000227711360574160400214220ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_EVAL_PAR_HH__ #define __MINIZINC_EVAL_PAR_HH__ #include #include #include #include namespace MiniZinc { /// Evaluate par int expression \a e IntVal eval_int(EnvI& env, Expression* e); /// Evaluate par bool expression \a e bool eval_bool(EnvI& env, Expression* e); /// Evaluate par float expression \a e FloatVal eval_float(EnvI& env, Expression* e); /// Evaluate an array expression \a e into an array literal ArrayLit* eval_array_lit(EnvI& env, Expression* e); /// Evaluate an access to array \a with indices \a idx and return whether /// access succeeded in \a success Expression* eval_arrayaccess(EnvI& env, ArrayLit* a, const std::vector& idx, bool& success); /// Evaluate an array access \a e and return whether access succeeded in \a success Expression* eval_arrayaccess(EnvI& env, ArrayAccess* e, bool& success); /// Evaluate a par integer set \a e IntSetVal* eval_intset(EnvI& env, Expression* e); /// Evaluate a par bool set \a e IntSetVal* eval_boolset(EnvI& env, Expression* e); /// Evaluate a par float set \a e FloatSetVal* eval_floatset(EnvI& env, Expression* e); /// Evaluate a par string \a e std::string eval_string(EnvI& env, Expression* e); /// Evaluate a par expression \a e and return it wrapped in a literal Expression* eval_par(EnvI& env, Expression* e); /// Check if expression \a e satisfies the domain constraint \a domain bool checkParDomain(EnvI& env, Expression* e, Expression* domain); /// Representation for bounds of an integer expression struct IntBounds { /// Lower bound IntVal l; /// Upper bound IntVal u; /// Whether the bounds are valid bool valid; /// Constructor IntBounds(IntVal l0, IntVal u0, bool valid0) : l(l0), u(u0), valid(valid0) {} }; /// Compute bounds of an integer expression IntBounds compute_int_bounds(EnvI& env, Expression* e); /// Representation for bounds of a float expression struct FloatBounds { /// Lower bound FloatVal l; /// Upper bound FloatVal u; /// Whether the bounds are valid bool valid; /// Constructor FloatBounds(FloatVal l0, FloatVal u0, bool valid0) : l(l0), u(u0), valid(valid0) {} }; /// Compute bounds of an integer expression FloatBounds compute_float_bounds(EnvI& env, Expression* e); /** * \brief Compute bounds of a set of int expression * * Returns NULL if bounds cannot be determined */ IntSetVal* compute_intset_bounds(EnvI& env, Expression* e); template void eval_comp_array(EnvI& env, Eval& eval, Comprehension* e, int gen, int id, KeepAlive in, std::vector& a); template void eval_comp_set(EnvI& env, Eval& eval, Comprehension* e, int gen, int id, KeepAlive in, std::vector& a); template void eval_comp_set(EnvI& env, Eval& eval, Comprehension* e, int gen, int id, IntVal i, KeepAlive in, std::vector& a) { { GCLock lock; GC::mark(); e->decl(gen,id)->trail(); e->decl(gen,id)->e(IntLit::a(i)); } CallStackItem csi(env, e->decl(gen,id)->id(), i); if (id == e->n_decls(gen)-1) { bool where = true; if (e->where(gen) != NULL) { GCLock lock; where = e->where(gen)->type().isvar() ? true : eval_bool(env, e->where(gen)); } if (where) { if (gen == e->n_generators()-1) { a.push_back(eval.e(env,e->e())); } else { if (e->in(gen+1)==NULL) { eval_comp_array(env, eval,e,gen+1,0,0,e->in(gen+1),a); } else { KeepAlive nextin; if (e->in(gen+1)->type().dim()==0) { GCLock lock; nextin = new SetLit(Location(),eval_intset(env, e->in(gen+1))); } else { GCLock lock; nextin = eval_array_lit(env, e->in(gen+1)); } if (e->in(gen+1)->type().dim()==0) { eval_comp_set(env, eval,e,gen+1,0,nextin,a); } else { eval_comp_array(env, eval,e,gen+1,0,nextin,a); } } } } } else { eval_comp_set(env, eval,e,gen,id+1,in,a); } GC::untrail(); e->decl(gen,id)->flat(NULL); } template void eval_comp_array(EnvI& env, Eval& eval, Comprehension* e, int gen, int id, IntVal i, KeepAlive in, std::vector& a) { GC::mark(); e->decl(gen,id)->trail(); CallStackItem csi(env, e->decl(gen,id)->id(), i); if (in()==NULL) { // this is an assignment generator Expression* asn = e->where(gen)->type().ispar() ? eval_par(env, e->where(gen)) : eval.flatten(env,e->where(gen)); e->decl(gen,id)->e(asn); e->rehash(); } else { ArrayLit* al = in()->cast(); e->decl(gen,id)->e((*al)[static_cast(i.toInt())]); e->rehash(); } if (id == e->n_decls(gen)-1) { bool where = true; if (e->in(gen) != NULL && e->where(gen) != NULL) { GCLock lock; where = e->where(gen)->type().isvar() ? true : eval_bool(env, e->where(gen)); } if (where) { if (gen == e->n_generators()-1) { a.push_back(eval.e(env,e->e())); } else { if (e->in(gen+1)==NULL) { eval_comp_array(env, eval,e,gen+1,0,0,e->in(gen+1),a); } else { KeepAlive nextin; if (e->in(gen+1)->type().dim()==0) { GCLock lock; nextin = new SetLit(Location(),eval_intset(env,e->in(gen+1))); } else { GCLock lock; nextin = eval_array_lit(env, e->in(gen+1)); } if (e->in(gen+1)->type().dim()==0) { eval_comp_set(env, eval,e,gen+1,0,nextin,a); } else { eval_comp_array(env, eval,e,gen+1,0,nextin,a); } } } } } else { eval_comp_array(env, eval,e,gen,id+1,in,a); } GC::untrail(); e->decl(gen,id)->flat(NULL); } /** * \brief Evaluate comprehension expression * * Calls \a eval.e for every element of the comprehension \a e, * where \a gen is the current generator, \a id is the current identifier * in that generator, \a in is the expression of that generator, and * \a a is the array in which to place the result. */ template void eval_comp_set(EnvI& env, Eval& eval, Comprehension* e, int gen, int id, KeepAlive in, std::vector& a) { IntSetVal* isv = eval_intset(env, in()); if (isv->card().isPlusInfinity()) { throw EvalError(env,in()->loc(),"comprehension iterates over an infinite set"); } IntSetRanges rsi(isv); Ranges::ToValues rsv(rsi); for (; rsv(); ++rsv) { eval_comp_set(env, eval,e,gen,id,rsv.val(),in,a); } } /** * \brief Evaluate comprehension expression * * Calls \a eval.e for every element of the comprehension \a e, * where \a gen is the current generator, \a id is the current identifier * in that generator, \a in is the expression of that generator, and * \a a is the array in which to place the result. */ template void eval_comp_array(EnvI& env, Eval& eval, Comprehension* e, int gen, int id, KeepAlive in, std::vector& a) { ArrayLit* al = in()->cast(); for (unsigned int i=0; isize(); i++) { eval_comp_array(env, eval,e,gen,id,i,in,a); } } /** * \brief Evaluate comprehension expression * * Calls \a eval.e for every element of the comprehension \a e and * returns a vector with all the evaluated results. */ template std::vector eval_comp(EnvI& env, Eval& eval, Comprehension* e) { std::vector a; if (e->in(0)==NULL) { eval_comp_array(env, eval,e,0,0,0,e->in(0),a); } else { KeepAlive in; { GCLock lock; if (e->in(0)->type().dim()==0) { if (e->in(0)->type().isvar()) { in = new SetLit(Location(),compute_intset_bounds(env, e->in(0))); } else { in = new SetLit(Location(),eval_intset(env, e->in(0))); } } else { in = eval_array_lit(env, e->in(0)); } } if (e->in(0)->type().dim()==0) { eval_comp_set(env, eval,e,0,0,in,a); } else { eval_comp_array(env, eval,e,0,0,in,a); } } return a; } /** * \brief Evaluate comprehension expression * * Calls \a Eval::e for every element of the comprehension \a e and * returns a vector with all the evaluated results. */ template std::vector eval_comp(EnvI& env, Comprehension* e) { Eval eval; return eval_comp(env, eval,e); } Expression* follow_id(Expression* e); Expression* follow_id_to_decl(Expression* e); Expression* follow_id_to_value(Expression* e); } #endif libminizinc-2.4.2/include/minizinc/exception.hh000066400000000000000000000036531360574160400216250ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_EXCEPTION_HH__ #define __MINIZINC_EXCEPTION_HH__ #include #include namespace MiniZinc { class Exception : public std::exception { protected: std::string _msg; public: Exception(const std::string& msg) : _msg(msg) {} virtual ~Exception(void) throw() {} virtual const char* what(void) const throw() = 0; const std::string& msg(void) const { return _msg; } }; class ParseException : public Exception { public: ParseException(const std::string& msg) : Exception(msg) {} ~ParseException(void) throw() {} virtual const char* what(void) const throw() { return ""; } }; class InternalError : public Exception { public: InternalError(const std::string& msg) : Exception(msg) {} ~InternalError(void) throw() {} virtual const char* what(void) const throw() { return "MiniZinc: internal error"; } }; class Error : public Exception { public: Error(const std::string& msg) : Exception(msg) {} ~Error(void) throw() {} virtual const char* what(void) const throw() { return ""; } }; class Timeout : public Exception { public: Timeout(void) : Exception("time limit reached") {} ~Timeout(void) throw() {} virtual const char* what(void) const throw() { return "MiniZinc: time out"; } }; class ArithmeticError : public Exception { public: ArithmeticError(const std::string& msg) : Exception(msg) {} virtual ~ArithmeticError(void) throw() {} virtual const char* what(void) const throw() { return "MiniZinc: arithmetic error"; } }; } #endif libminizinc-2.4.2/include/minizinc/file_utils.hh000066400000000000000000000066231360574160400217660ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_FILE_UTILS_HH__ #define __MINIZINC_FILE_UTILS_HH__ #include #include namespace MiniZinc { namespace FileUtils { /// Return full path to current executable std::string progpath(void); /// Test if \a filename exists bool file_exists(const std::string& filename); /// Test if \a dirname exists and is a directory bool directory_exists(const std::string& dirname); /// Find executable \a filename anywhere on the path /// On Windows, also check extensions .exe and .bat std::string find_executable(const std::string& filename); /// Return full path to file. If \a basePath is not empty, also try resolving /// relative paths with respect to \a basePath. std::string file_path(const std::string& filename, const std::string& basePath=std::string()); /// Return directory name containing \a filename std::string dir_name(const std::string& filename); /// Return base name of \a filename (without dir_name) std::string base_name(const std::string& filename); /// Check whether path is absolute bool is_absolute(const std::string& path); /// Return list of files with extension \a ext in directory \a dir std::vector directory_list(const std::string& dir, const std::string& ext=std::string("*")); /// Return share/minizinc directory if present anywhere above the executable std::string share_directory(void); /// Return current working directory std::string working_directory(void); /// Get global configuration file name (in share/minizinc directory) std::string global_config_file(void); /// Get per-user configuration file name (usually in home directory or AppData directory) std::string user_config_file(void); /// Get per-user configuration directory name (usually in home directory or AppData directory) std::string user_config_dir(void); /// Parse command line \a s into individual arguments std::vector parseCmdLine(const std::string& s); /// Combine individual arguments \a cmd into properly quoted command line std::string combineCmdLine(const std::vector& cmd); /// Create a temporary file class TmpFile { private: std::string _name; #ifdef _WIN32 std::vector _tmpNames; #endif #ifndef _WIN32 int _tmpfile_desc; #endif public: // Constructor for file with extension \a ext TmpFile(const std::string& ext); /// Destructor (removes file) ~TmpFile(void); std::string name(void) const { return _name; } }; /// Create a temporary directory class TmpDir { private: std::string _name; public: // Constructor for difrectory TmpDir(void); /// Destructor (removes directory) ~TmpDir(void); std::string name(void) const { return _name; } }; /// Inflate string \a s void inflateString(std::string& s); /// Deflate string \a s std::string deflateString(const std::string& s); /// Encode string into base 64 std::string encodeBase64(const std::string& s); /// Decode string from base 64 std::string decodeBase64(const std::string& s); }} #endif libminizinc-2.4.2/include/minizinc/flat_exp.hh000066400000000000000000000024041360574160400214220ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_FLAT_EXP_HH__ #define __MINIZINC_FLAT_EXP_HH__ #include namespace MiniZinc { void addPathAnnotation(EnvI& env, Expression* e); void addCtxAnn(VarDecl* vd, BCtx& c); bool istrue(EnvI& env, Expression* e); bool isfalse(EnvI& env, Expression* e); Expression* createDummyValue(EnvI& env, const Type& t); TypeInst* eval_typeinst(EnvI& env, VarDecl* vd); KeepAlive bind(EnvI& env, Ctx ctx, VarDecl* vd, Expression* e); KeepAlive conj(EnvI& env,VarDecl* b,Ctx ctx,const std::vector& e); VarDecl* newVarDecl(EnvI& env, Ctx ctx, TypeInst* ti, Id* origId, VarDecl* origVd, Expression* rhs); KeepAlive flat_cv_exp(EnvI& env, Ctx ctx, Expression* e); void makeDefinedVar(VarDecl* vd, Call* c); void checkIndexSets(EnvI& env, VarDecl* vd, Expression* e); class CallArgItem { public: EnvI& env; CallArgItem(EnvI& env0); ~CallArgItem(void); }; } #endif libminizinc-2.4.2/include/minizinc/flatten.hh000066400000000000000000000075261360574160400212670ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_FLATTEN_HH__ #define __MINIZINC_FLATTEN_HH__ #include #include namespace MiniZinc { /// Exception thrown for errors during flattening class FlatteningError : public LocationException { public: FlatteningError(EnvI& env, const Location& loc, const std::string& msg); ~FlatteningError(void) throw() {} virtual const char* what(void) const throw() { return "MiniZinc: flattening error"; } }; /// Options for the flattener struct FlatteningOptions { /// Keep output in resulting flat model bool keepOutputInFzn; /// Verbose output during flattening bool verbose; /// Only use paths for variables introduced by file 0 (the MiniZinc model) bool only_toplevel_paths; /// Construct and collect mzn_paths for expressions and VarDeclI during flattening bool collect_mzn_paths; /// Do not apply domain changes but insert them as constraints (useful for debugging) bool record_domain_changes; /// Only range domains for old linearization. Set from redefs to true if not here bool onlyRangeDomains; /// Allow the use of Half Reifications bool enable_imp; /// Timeout for flattening in milliseconds (0 means no timeout) unsigned long long int timeout; /// Create standard, DZN or JSON output enum OutputMode { OUTPUT_ITEM, OUTPUT_DZN, OUTPUT_JSON } outputMode; /// Output objective value (only for DZN and JSON mode) bool outputObjective; /// Output original output item as string (only for DZN and JSON mode) bool outputOutputItem; /// Output detailed timing information for flattening bool detailedTiming; /// Default constructor FlatteningOptions(void) : keepOutputInFzn(false), verbose(false), only_toplevel_paths(false), collect_mzn_paths(false), record_domain_changes(false), onlyRangeDomains(false), enable_imp(true), timeout(0), outputMode(OUTPUT_ITEM), outputObjective(false), outputOutputItem(false), detailedTiming(false) {} }; class Pass { public: Pass() {}; virtual Env* run(Env* env, std::ostream& log) = 0; virtual ~Pass() {}; }; /// Flatten model \a m void flatten(Env& m, FlatteningOptions opt = FlatteningOptions()); /// Translate \a m into old FlatZinc syntax void oldflatzinc(Env& m); /// Populate FlatZinc output model void populateOutput(Env& e); /// Statistics on flat models struct FlatModelStatistics { /// Number of integer variables int n_int_vars; /// Number of bool variables int n_bool_vars; /// Number of float variables int n_float_vars; /// Number of set variables int n_set_vars; /// Number of bool constraints int n_bool_ct; /// Number of integer constraints int n_int_ct; /// Number of float constraints int n_float_ct; /// Number of set constraints int n_set_ct; /// Number of reified constraints evaluated int n_reif_ct; /// Number of half-reified constraints evaluated int n_imp_ct; /// Number of implications eliminated using path compression int n_imp_del; /// Number of linear expressions eliminated using path compression int n_lin_del; /// Constructor FlatModelStatistics(void) : n_int_vars(0), n_bool_vars(0), n_float_vars(0), n_set_vars(0), n_bool_ct(0), n_int_ct(0), n_float_ct(0), n_set_ct(0), n_reif_ct(0), n_imp_ct(0), n_imp_del(0), n_lin_del(0) {} }; /// Compute statistics for flat model in \a m FlatModelStatistics statistics(Env& m); } #endif libminizinc-2.4.2/include/minizinc/flatten_internal.hh000066400000000000000000000377411360574160400231650ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_FLATTEN_INTERNAL_HH__ #define __MINIZINC_FLATTEN_INTERNAL_HH__ #include #include #include #include #include namespace MiniZinc { /// Result of evaluation class EE { public: /// The result value KeepAlive r; /// Boolean expression representing whether result is defined KeepAlive b; /// Constructor explicit EE(Expression* r0=NULL, Expression* b0=NULL) : r(r0), b(b0) {} }; /// Boolean evaluation context enum BCtx { C_ROOT, C_POS, C_NEG, C_MIX }; /// Evaluation context struct Ctx { /// Boolean context BCtx b; /// Integer context BCtx i; /// Boolen negation flag bool neg; /// Default constructor (root context) Ctx(void) : b(C_ROOT), i(C_MIX), neg(false) {} /// Copy constructor Ctx(const Ctx& ctx) : b(ctx.b), i(ctx.i), neg(ctx.neg) {} /// Assignment operator Ctx& operator =(const Ctx& ctx) { if (this!=&ctx) { b = ctx.b; i = ctx.i; neg = ctx.neg; } return *this; } }; /// Turn \a c into positive context BCtx operator +(const BCtx& c); /// Negate context \a c BCtx operator -(const BCtx& c); class EnvI { public: Model* model; Model* orig_model; Model* output; VarOccurrences vo; VarOccurrences output_vo; std::ostream& outstream; std::ostream& errstream; // The current pass number (used for unifying and disabling path construction in final pass) unsigned int current_pass_no; // Used for disabling path construction in final pass unsigned int final_pass_no; // Used for disabling path construction past the maxPathDepth of previous passes unsigned int maxPathDepth; VarOccurrences output_vo_flat; CopyMap cmap; IdMap reverseMappers; struct WW { WeakRef r; WeakRef b; WW(WeakRef r0, WeakRef b0) : r(r0), b(b0) {} }; typedef KeepAliveMap CSEMap; bool ignorePartial; bool ignoreUnknownIds; std::vector callStack; std::vector > errorStack; std::vector idStack; unsigned int maxCallStack; std::vector warnings; bool collect_vardecls; std::vector modifiedVarDecls; std::unordered_set deprecationWarnings; int in_redundant_constraint; int in_maybe_partial; int n_reif_ct; int n_imp_ct; int n_imp_del; int n_lin_del; bool in_reverse_map_var; FlatteningOptions fopts; unsigned int pathUse; std::unordered_map reverseEnum; struct PathVar { KeepAlive decl; unsigned int pass_no; }; // Store mapping from path string to (VarDecl, pass_no) tuples typedef std::unordered_map PathMap; // Mapping from arbitrary Expressions to paths typedef KeepAliveMap ReversePathMap; // Map from filename to integer (space saving optimisation) typedef std::unordered_map FilenameMap; std::vector checkVars; protected: CSEMap cse_map; Model* _flat; bool _failed; unsigned int ids; ASTStringMap::t reifyMap; PathMap pathMap; ReversePathMap reversePathMap; FilenameMap filenameMap; typedef std::unordered_map EnumMap; EnumMap enumMap; std::vector enumVarDecls; typedef std::unordered_map ArrayEnumMap; ArrayEnumMap arrayEnumMap; std::vector > arrayEnumDecls; public: EnvI(Model* orig0, std::ostream& outstream0=std::cout, std::ostream& errstream0=std::cerr); ~EnvI(void); long long int genId(void); /// Set minimum new temporary id to \a i+1 void minId(unsigned int i) { ids = std::max(ids, i+1); } void cse_map_insert(Expression* e, const EE& ee); CSEMap::iterator cse_map_find(Expression* e); void cse_map_remove(Expression* e); CSEMap::iterator cse_map_end(void); void dump(void); unsigned int registerEnum(VarDeclI* vdi); VarDeclI* getEnum(unsigned int i) const; unsigned int registerArrayEnum(const std::vector& arrayEnum); const std::vector& getArrayEnum(unsigned int i) const; /// Check if \a t1 is a subtype of \a t2 (including enumerated types if \a strictEnum is true) bool isSubtype(const Type& t1, const Type& t2, bool strictEnum); void flat_addItem(Item* i); void flat_removeItem(int i); void flat_removeItem(Item* i); void vo_add_exp(VarDecl* vd); void annotateFromCallStack(Expression* e); void fail(const std::string& msg = std::string()); bool failed(void) const; Model* flat(void); void swap(); void swap_output() { std::swap( model, output ); } ASTString reifyId(const ASTString& id); ASTString halfReifyId(const ASTString& id); std::ostream& dumpStack(std::ostream& os, bool errStack); bool dumpPath(std::ostream& os, bool force = false); void addWarning(const std::string& msg); void collectVarDecls(bool b); PathMap& getPathMap() { return pathMap; } ReversePathMap& getReversePathMap() { return reversePathMap; } FilenameMap& getFilenameMap() { return filenameMap; } void copyPathMapsAndState(EnvI& env); /// deprecated, use Solns2Out std::ostream& evalOutput(std::ostream& os); void createErrorStack(void); Call* surroundingCall(void) const; void cleanupExceptOutput(); }; void setComputedDomain(EnvI& envi, VarDecl* vd, Expression* domain, bool is_computed); EE flat_exp(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b); EE flatten_id(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b, bool doNotFollowChains); class CmpExpIdx { public: std::vector& x; CmpExpIdx(std::vector& x0) : x(x0) {} bool operator ()(int i, int j) const { if (Expression::equal(x[i](),x[j]())) return false; if (x[i]()->isa() && x[j]()->isa() && x[i]()->cast()->idn() != -1 && x[j]()->cast()->idn() != -1) return x[i]()->cast()->idn() < x[j]()->cast()->idn(); return x[i]() class LinearTraits { }; template<> class LinearTraits { public: typedef IntVal Val; static Val eval(EnvI& env, Expression* e) { return eval_int(env,e); } static void constructLinBuiltin(BinOpType bot, ASTString& callid, int& coeff_sign, Val& d) { switch (bot) { case BOT_LE: callid = constants().ids.int_.lin_le; coeff_sign = 1; d += 1; break; case BOT_LQ: callid = constants().ids.int_.lin_le; coeff_sign = 1; break; case BOT_GR: callid = constants().ids.int_.lin_le; coeff_sign = -1; d = -d+1; break; case BOT_GQ: callid = constants().ids.int_.lin_le; coeff_sign = -1; d = -d; break; case BOT_EQ: callid = constants().ids.int_.lin_eq; coeff_sign = 1; break; case BOT_NQ: callid = constants().ids.int_.lin_ne; coeff_sign = 1; break; default: assert(false); break; } } static ASTString id_eq(void) { return constants().ids.int_.eq; } typedef IntBounds Bounds; static bool finite(const IntBounds& ib) { return ib.l.isFinite() && ib.u.isFinite(); } static bool finite(const IntVal& v) { return v.isFinite(); } static Bounds compute_bounds(EnvI& env, Expression* e) { return compute_int_bounds(env,e); } typedef IntSetVal* Domain; static Domain eval_domain(EnvI& env, Expression* e) { return eval_intset(env, e); } static Expression* new_domain(Val v) { return new SetLit(Location().introduce(),IntSetVal::a(v,v)); } static Expression* new_domain(Val v0, Val v1) { return new SetLit(Location().introduce(),IntSetVal::a(v0,v1)); } static Expression* new_domain(Domain d) { return new SetLit(Location().introduce(),d); } static bool domain_contains(Domain dom, Val v) { return dom->contains(v); } static bool domain_equals(Domain dom, Val v) { return dom->size()==1 && dom->min(0)==v && dom->max(0)==v; } static bool domain_equals(Domain dom1, Domain dom2) { IntSetRanges d1(dom1); IntSetRanges d2(dom2); return Ranges::equal(d1,d2); } static bool domain_tighter(Domain dom, Bounds b) { return !b.valid || dom->min() > b.l || dom->max() < b.u; } static bool domain_intersects(Domain dom, Val v0, Val v1) { return (v0 > v1) || (dom->size() > 0 && dom->min(0) <= v1 && v0 <= dom->max(dom->size()-1)); } static bool domain_empty(Domain dom) { return dom->size()==0; } static Domain limit_domain(BinOpType bot, Domain dom, Val v) { IntSetRanges dr(dom); IntSetVal* ndomain; switch (bot) { case BOT_LE: v -= 1; // fall through case BOT_LQ: { Ranges::Bounded b = Ranges::Bounded::maxiter(dr,v); ndomain = IntSetVal::ai(b); } break; case BOT_GR: v += 1; // fall through case BOT_GQ: { Ranges::Bounded b = Ranges::Bounded::miniter(dr,v); ndomain = IntSetVal::ai(b); } break; case BOT_NQ: { Ranges::Const c(v,v); Ranges::Diff > d(dr,c); ndomain = IntSetVal::ai(d); } break; default: assert(false); return NULL; } return ndomain; } static Domain intersect_domain(Domain dom, Val v0, Val v1) { IntSetRanges dr(dom); Ranges::Const c(v0,v1); Ranges::Inter > inter(dr,c); return IntSetVal::ai(inter); } static Val floor_div(Val v0, Val v1) { return static_cast(floor(static_cast(v0.toInt()) / static_cast(v1.toInt()))); } static Val ceil_div(Val v0, Val v1) { return static_cast(ceil(static_cast(v0.toInt()) / v1.toInt())); } static IntLit* newLit(Val v) { return IntLit::a(v); } }; template<> class LinearTraits { public: typedef FloatVal Val; static Val eval(EnvI& env, Expression* e) { return eval_float(env,e); } static void constructLinBuiltin(BinOpType bot, ASTString& callid, int& coeff_sign, Val& d) { switch (bot) { case BOT_LE: callid = constants().ids.float_.lin_lt; coeff_sign = 1; break; case BOT_LQ: callid = constants().ids.float_.lin_le; coeff_sign = 1; break; case BOT_GR: callid = constants().ids.float_.lin_lt; coeff_sign = -1; d = -d; break; case BOT_GQ: callid = constants().ids.float_.lin_le; coeff_sign = -1; d = -d; break; case BOT_EQ: callid = constants().ids.float_.lin_eq; coeff_sign = 1; break; case BOT_NQ: callid = constants().ids.float_.lin_ne; coeff_sign = 1; break; default: assert(false); break; } } static ASTString id_eq(void) { return constants().ids.float_.eq; } typedef FloatBounds Bounds; static bool finite(const FloatBounds& ib) { return ib.l.isFinite() && ib.u.isFinite(); } static bool finite(const FloatVal& v) { return v.isFinite(); } static Bounds compute_bounds(EnvI& env, Expression* e) { return compute_float_bounds(env,e); } typedef FloatSetVal* Domain; static Domain eval_domain(EnvI& env, Expression* e) { return eval_floatset(env, e); } static Expression* new_domain(Val v) { return new SetLit(Location().introduce(),FloatSetVal::a(v,v)); } static Expression* new_domain(Val v0, Val v1) { return new SetLit(Location().introduce(),FloatSetVal::a(v0,v1)); } static Expression* new_domain(Domain d) { return new SetLit(Location().introduce(),d); } static bool domain_contains(Domain dom, Val v) { return dom->contains(v); } static bool domain_equals(Domain dom, Val v) { return dom->size()==1 && dom->min(0)==v && dom->max(0)==v; } static bool domain_tighter(Domain dom, Bounds b) { return !b.valid || dom->min() > b.l || dom->max() < b.u; } static bool domain_intersects(Domain dom, Val v0, Val v1) { return (v0 > v1) || (dom->size() > 0 && dom->min(0) <= v1 && v0 <= dom->max(dom->size()-1)); } static bool domain_empty(Domain dom) { return dom->size()==0; } static bool domain_equals(Domain dom1, Domain dom2) { FloatSetRanges d1(dom1); FloatSetRanges d2(dom2); return Ranges::equal(d1,d2); } static Domain intersect_domain(Domain dom, Val v0, Val v1) { if (dom) { FloatSetRanges dr(dom); Ranges::Const c(v0,v1); Ranges::Inter > inter(dr,c); return FloatSetVal::ai(inter); } else { Domain d = FloatSetVal::a(v0,v1); return d; } } static Domain limit_domain(BinOpType bot, Domain dom, Val v) { FloatSetRanges dr(dom); FloatSetVal* ndomain; switch (bot) { case BOT_LE: return NULL; case BOT_LQ: { Ranges::Bounded b = Ranges::Bounded::maxiter(dr,v); ndomain = FloatSetVal::ai(b); } break; case BOT_GR: return NULL; case BOT_GQ: { Ranges::Bounded b = Ranges::Bounded::miniter(dr,v); ndomain = FloatSetVal::ai(b); } break; case BOT_NQ: { Ranges::Const c(v,v); Ranges::Diff > d(dr,c); ndomain = FloatSetVal::ai(d); } break; default: assert(false); return NULL; } return ndomain; } static Val floor_div(Val v0, Val v1) { return v0 / v1; } static Val ceil_div(Val v0, Val v1) { return v0 / v1; } static FloatLit* newLit(Val v) { return FloatLit::a(v); } }; template void simplify_lin(std::vector::Val>& c, std::vector& x, typename LinearTraits::Val& d) { std::vector idx(c.size()); for (unsigned int i=static_cast(idx.size()); i--;) { idx[i]=i; Expression* e = follow_id_to_decl(x[i]()); if (VarDecl* vd = e->dyn_cast()) { if (vd->e() && vd->e()->isa()) { x[i] = vd->e(); } else { x[i] = e->cast()->id(); } } else { x[i] = e; } } std::sort(idx.begin(),idx.end(),CmpExpIdx(x)); unsigned int ci = 0; for (; cidyn_cast()) { d += c[idx[ci]]*il->v(); c[idx[ci]] = 0; } else { break; } } for (unsigned int i=ci+1; idyn_cast()) { d += c[idx[i]]*il->v(); c[idx[i]] = 0; } else { ci=i; } } ci = 0; for (unsigned int i=0; i * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_FLATTENER_H__ #define __MINIZINC_FLATTENER_H__ #include #include #include #include #include #include #include #include #include #include #include // temp., TODO #include #include #include #include #include #include #include #include #include #ifdef HAS_GECODE #include #endif namespace MiniZinc { class Flattener { private: std::unique_ptr pEnv; std::ostream& os; std::ostream& log; public: Flattener(std::ostream& os, std::ostream& log, const std::string& stdlibDir); ~Flattener(); bool processOption(int& i, std::vector& argv); void printVersion(std::ostream& ); void printHelp(std::ostream& ); void flatten(const std::string& modelString = std::string(), const std::string& modelName = std::string("stdin")); void printStatistics(std::ostream& ); void set_flag_verbose(bool f) { flag_verbose = f; } bool get_flag_verbose() const { return flag_verbose; } void set_flag_statistics(bool f) { flag_statistics = f; } bool get_flag_statistics() const { return flag_statistics; } void set_flag_timelimit(unsigned long long int t) { fopts.timeout = t; } unsigned long long int get_flag_timelimit(void) { return fopts.timeout; } void set_flag_output_by_default(bool f) { fOutputByDefault = f; } Env* getEnv() const { assert(pEnv.get()); return pEnv.get(); } bool hasInputFiles(void) const { return !filenames.empty() || flag_stdinInput || !flag_solution_check_model.empty(); } SolverInstance::Status status = SolverInstance::UNKNOWN; private: Env* multiPassFlatten(const std::vector >& passes); bool fOutputByDefault = false; // if the class is used in mzn2fzn, write .fzn+.ozn by default std::vector filenames; std::vector datafiles; std::vector includePaths; bool is_flatzinc = false; bool flag_ignoreStdlib = false; bool flag_typecheck = true; bool flag_verbose = false; bool flag_newfzn = false; bool flag_optimize = true; bool flag_chain_compression = true; bool flag_werror = false; bool flag_only_range_domains = false; bool flag_allow_unbounded_vars = false; bool flag_noMIPdomains = false; int opt_MIPDmaxIntvEE = 0; double opt_MIPDmaxDensEE = 0.0; bool flag_statistics = false; bool flag_stdinInput = false; bool flag_allow_multi_assign = false; bool flag_gecode = false; bool flag_two_pass = false; bool flag_sac = false; bool flag_shave = false; unsigned int flag_pre_passes = 1; std::string std_lib_dir; std::string globals_dir; bool flag_no_output_ozn = false; std::string flag_output_base; std::string flag_output_fzn; std::string flag_output_ozn; std::string flag_output_paths; bool flag_keep_mzn_paths = false; bool flag_output_fzn_stdout = false; bool flag_output_ozn_stdout = false; bool flag_output_paths_stdout = false; bool flag_instance_check_only = false; bool flag_model_check_only = false; bool flag_model_interface_only = false; bool flag_model_types_only = false; FlatteningOptions::OutputMode flag_output_mode = FlatteningOptions::OUTPUT_ITEM; bool flag_output_objective = false; bool flag_output_output_item = false; std::string flag_solution_check_model; bool flag_compile_solution_check_model = false; FlatteningOptions fopts; Timer starttime; }; } #endif // __MINIZINC_FLATTENER_H__ libminizinc-2.4.2/include/minizinc/gc.hh000066400000000000000000000141561360574160400202200ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_GC_HH__ #define __MINIZINC_GC_HH__ #include #include #include #include #include #include namespace MiniZinc { /** * \brief Base class for abstract syntax tree nodes */ class ASTNode { friend class GC; protected: /// Mark for garbage collection mutable unsigned int _gc_mark : 1; /// Id of the node unsigned int _id : 7; /// Secondary id unsigned int _sec_id : 7; /// Flag unsigned int _flag_1 : 1; /// Flag unsigned int _flag_2 : 1; enum BaseNodes { NID_FL, NID_CHUNK, NID_VEC, NID_END = NID_VEC }; /// Constructor ASTNode(unsigned int id) : _gc_mark(0), _id(id) {} public: /// Allocate node void* operator new(size_t size); /// Placement-new void* operator new(size_t, void* n) throw() { return n; } /// Delete node (no-op) void operator delete(void*, size_t) throw() { } /// Delete node (no-op) void operator delete(void*, void*) throw() { } /// Delete node (no-op) void operator delete(void*) throw() {} }; /** * \brief Base class for unstructured garbage collected data */ class ASTChunk : public ASTNode { friend class GC; protected: /// Allocated size size_t _size; /// Storage char _data[4]; /// Constructor ASTChunk(size_t size); /// Actual size of object in memory size_t memsize(void) const { size_t s = sizeof(ASTChunk)+(_size<=4?0:_size-4)*sizeof(char); s += ((8 - (s & 7)) & 7); return s; } /// Allocate raw memory static void* alloc(size_t size); }; /** * \brief Base class for structured garbage collected data */ class ASTVec : public ASTNode { friend class GC; protected: /// Allocated size size_t _size; /// Storage void* _data[2]; /// Constructor ASTVec(size_t size); /// Actual size of object in memory size_t memsize(void) const { size_t s = sizeof(ASTVec)+(_size<=2?0:_size-2)*sizeof(void*); s += ((8 - (s & 7)) & 7); return s; } /// Allocate raw memory static void* alloc(size_t size); }; class Model; class Expression; class KeepAlive; class WeakRef; class ASTNodeWeakMap; /// Garbage collector class GC { friend class ASTNode; friend class ASTVec; friend class ASTChunk; friend class KeepAlive; friend class WeakRef; friend class ASTNodeWeakMap; private: class Heap; /// The memory controlled by the collector Heap* _heap; /// Count how many locks are currently active unsigned int _lock_count; /// Timeout in milliseconds unsigned long long int _timeout; /// Counter for timeout int _timeout_counter; /// Timer for timeout Timer _timeout_timer; /// Return thread-local GC object static GC*& gc(void); /// Constructor GC(void); /// Allocate garbage collected memory void* alloc(size_t size); static void addKeepAlive(KeepAlive* e); static void removeKeepAlive(KeepAlive* e); static void addWeakRef(WeakRef* e); static void removeWeakRef(WeakRef* e); static void addNodeWeakMap(ASTNodeWeakMap* m); static void removeNodeWeakMap(ASTNodeWeakMap* m); public: /// Acquire garbage collector lock for this thread static void lock(void); /// Release garbage collector lock for this thread static void unlock(void); /// Manually trigger garbage collector (must be unlocked) static void trigger(void); /// Test if garbage collector is locked static bool locked(void); /// Add model \a m to root set static void add(Model* m); /// Remove model \a m from root set static void remove(Model* m); /// Put a mark on the trail static void mark(void); /// Add a trail entry static void trail(Expression**,Expression*); /// Untrail to previous mark static void untrail(void); /// Set timeout of \a t milliseconds, 0 means disable static void setTimeout(unsigned long long int t); /// Return maximum allocated memory (high water mark) static size_t maxMem(void); }; /// Automatic garbage collection lock class GCLock { public: /// Acquire lock GCLock(void); /// Release lock upon destruction ~GCLock(void); }; /// Expression wrapper that is a member of the root set class KeepAlive { friend class GC; private: Expression* _e; KeepAlive* _p; KeepAlive* _n; public: KeepAlive(Expression* e = NULL); ~KeepAlive(void); KeepAlive(const KeepAlive& e); KeepAlive& operator =(const KeepAlive& e); Expression* operator ()(void) { return _e; } Expression* operator ()(void) const { return _e; } KeepAlive* next(void) const { return _n; } }; /// Expression wrapper that is a member of the root set class WeakRef { friend class GC; private: Expression* _e; WeakRef* _p; WeakRef* _n; bool _valid; public: WeakRef(Expression* e = NULL); ~WeakRef(void); WeakRef(const WeakRef& e); WeakRef& operator =(const WeakRef& e); Expression* operator ()(void) { return _valid ? _e : NULL; } Expression* operator ()(void) const { return _valid ? _e : NULL; } WeakRef* next(void) const { return _n; } }; class ASTNodeWeakMap { friend class GC; private: ASTNodeWeakMap(const WeakRef& e); ASTNodeWeakMap& operator =(const ASTNodeWeakMap& e); protected: typedef std::unordered_map NodeMap; ASTNodeWeakMap* _p; ASTNodeWeakMap* _n; ASTNodeWeakMap* next(void) const { return _n; } NodeMap _m; public: ASTNodeWeakMap(void); ~ASTNodeWeakMap(void); void insert(ASTNode* n0, ASTNode* n1); ASTNode* find(ASTNode* n); void clear() { _m.clear(); } }; } #endif libminizinc-2.4.2/include/minizinc/hash.hh000066400000000000000000000143151360574160400205470ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_HASH_HH__ #define __MINIZINC_HASH_HH__ #include #include #include #include namespace MiniZinc { /// Hash class for expressions struct ExpressionHash { size_t operator() (const Expression* e) const { return Expression::hash(e); } }; /// Equality test for expressions struct ExpressionEq { bool operator() (const Expression* e0, const Expression* e1) const { return Expression::equal(e0,e1); } }; /// Hash map from expression to \a T template class ExpressionMap { protected: /// The underlying map implementation std::unordered_map _m; public: /// Iterator type typedef typename std::unordered_map::iterator iterator; /// Insert mapping from \a e to \a t iterator insert(Expression* e, const T& t) { assert(e != NULL); return _m.insert(std::pair(e,t)).first; } /// Find \a e in map iterator find(Expression* e) { return _m.find(e); } /// Begin of iterator iterator begin(void) { return _m.begin(); } /// End of iterator iterator end(void) { return _m.end(); } /// Remove binding of \a e from map void remove(Expression* e) { _m.erase(e); } /// Remove all elements from the map void clear(void) { _m.clear(); } }; /// Equality test for identifiers struct IdEq { bool operator() (const Id* e0, const Id* e1) const { if (e0->idn() == e1->idn()) { if (e0->idn() == -1) return e0->v() == e1->v(); return true; } return false; } }; /// Hash map from identifier to \a T template class IdMap { protected: /// The underlying map implementation std::unordered_map _m; public: /// Iterator type typedef typename std::unordered_map::iterator iterator; /// Insert mapping from \a e to \a t void insert(Id* e, const T& t) { assert(e != NULL); _m.insert(std::pair(e,t)); } /// Find \a e in map iterator find(Id* e) { return _m.find(e); } /// Begin of iterator iterator begin(void) { return _m.begin(); } /// End of iterator iterator end(void) { return _m.end(); } /// Remove binding of \a e from map void remove(Id* e) { _m.erase(e); } /// Return number of elements in the map int size(void) const { return _m.size(); } /// Remove all elements from the map void clear(void) { _m.clear(); } T& get(Id* ident) { iterator it = find(ident); // assert(it != _m.end()); if (_m.end() == it) { // Changing so it stays in Release version std::string msg = "Id "; // if (ident) // could be a segfault... // msg += ident->v().c_str(); msg += " not found"; throw InternalError(msg); } return it->second; } }; /// Hash class for KeepAlive objects struct KAHash { size_t operator() (const KeepAlive& e) const { return Expression::hash(e()); } }; /// Equality test for KeepAlive objects struct KAEq { bool operator() (const KeepAlive& e0, const KeepAlive& e1) const { return Expression::equal(e0(),e1()); } }; /// Hash map from KeepAlive to \a T template class KeepAliveMap { protected: /// The underlying map implementation std::unordered_map _m; public: /// Iterator type typedef typename std::unordered_map::iterator iterator; /// Insert mapping from \a e to \a t void insert(KeepAlive& e, const T& t) { assert(e() != NULL); _m.insert(std::pair(e,t)); } /// Find \a e in map iterator find(KeepAlive& e) { return _m.find(e); } /// Begin of iterator iterator begin(void) { return _m.begin(); } /// End of iterator iterator end(void) { return _m.end(); } /// Remove binding of \a e from map void remove(KeepAlive& e) { _m.erase(e); } void clear() { _m.clear(); } template void dump(void) { for (iterator i = _m.begin(); i != _m.end(); ++i) { std::cerr << D::k(i->first()) << ": " << D::d(i->second) << std::endl; } } }; class ExpressionSetIter : public std::unordered_set::iterator { protected: bool _empty; typedef std::unordered_set::iterator Iter; public: ExpressionSetIter(void) : _empty(false) {} ExpressionSetIter(bool) : _empty(true) {} ExpressionSetIter(const Iter& i) : Iter(i), _empty(false) {} bool operator ==(const ExpressionSetIter& i) const { return (_empty && i._empty) || static_cast(*this)==static_cast(i); } bool operator !=(const ExpressionSetIter& i) const { return !operator ==(i); } }; /// Hash set for expressions class ExpressionSet { protected: /// The underlying set implementation std::unordered_set _s; public: /// Insert \a e void insert(Expression* e) { assert(e != NULL); _s.insert(e); } /// Find \a e in map ExpressionSetIter find(Expression* e) { return _s.find(e); } /// Begin of iterator ExpressionSetIter begin(void) { return _s.begin(); } /// End of iterator ExpressionSetIter end(void) { return _s.end(); } /// Remove binding of \a e from map void remove(Expression* e) { _s.erase(e); } bool contains(Expression* e) { return find(e) != end(); } /// Remove all elements from the map void clear(void) { _s.clear(); } bool isEmpty(void) const { return _s.begin() == _s.end(); } }; } #endif libminizinc-2.4.2/include/minizinc/htmlprinter.hh000066400000000000000000000026271360574160400221770ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_HTMLPRINTER_HH #define __MINIZINC_HTMLPRINTER_HH #include #include namespace MiniZinc { class Model; class HtmlDocument { protected: std::string _filename; std::string _title; std::string _doc; public: HtmlDocument(const std::string& filename, const std::string& title, const std::string& document) : _filename(filename), _title(title), _doc(document) {} std::string filename(void) const { return _filename; } std::string title(void) const { return _title; } std::string document(void) const { return _doc; } }; class HtmlPrinter { public: static std::vector printHtml(EnvI& env, Model* m, const std::string& basename, int splitLevel, bool includeStdLib, bool generateIndex); }; class RSTPrinter { public: static std::vector printRST(EnvI& env, Model* m, const std::string& basename, int splitLevel, bool includeStdLib, bool generateIndex); }; } #endif libminizinc-2.4.2/include/minizinc/iter.hh000066400000000000000000000440701360574160400205700ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_ITER_HH__ #define __MINIZINC_ITER_HH__ #include #include #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #undef ERROR // MICROsoft. #undef min #undef max #endif namespace MiniZinc { namespace Ranges { /** * \brief Base for range iterators with explicit min and max * * The iterator provides members \a mi and \a ma for storing the * limits of the currently iterated range. The iterator * continues until \a mi becomes greater than \a ma. The member function * finish does exactly that. * * \ingroup FuncIterRanges */ template class MinMax { protected: /// Minimum of current range Val mi; /// Maximum of current range Val ma; /// %Set range such that iteration stops void finish(void); public: /// \name Constructors and initialization //@{ /// Default constructor MinMax(void); /// Initialize with range \a min to \a max MinMax(Val min, Val max); //@} /// \name Iteration control //@{ /// Test whether iterator is still at a range or done bool operator ()(void) const; //@} /// \name Range access //@{ /// Return smallest value of range Val min(void) const; /// Return largest value of range Val max(void) const; /// Return width of range (distance between minimum and maximum) Val width(void) const; //@} }; template inline void MinMax::finish(void) { mi = 1; ma = 0; } template inline MinMax::MinMax(void) {} template inline MinMax::MinMax(Val min, Val max) : mi(min), ma(max) {} template inline bool MinMax::operator ()(void) const { return mi <= ma; } template inline Val MinMax::min(void) const { return mi; } template inline Val MinMax::max(void) const { return ma; } template inline Val MinMax::width(void) const { if (mi > ma) return 0; if (mi.isFinite() && ma.isFinite()) return ma-mi+1; return Val::infinity(); } template class Bounded { protected: I i; Val _min; bool use_min; Val _max; bool use_max; Bounded(I& i, Val min0, bool umin0, Val max0, bool umax0); public: static Bounded miniter(I& i, Val min); static Bounded maxiter(I& i, Val max); static Bounded minmaxiter(I& i, Val min, Val max); /// \name Iteration control //@{ /// Test whether iterator is still at a range or done bool operator ()(void) const; /// Move iterator to next range (if possible) void operator ++(void); //@} /// \name Range access //@{ /// Return smallest value of range Val min(void) const; /// Return largest value of range Val max(void) const; /// Return width of range (distance between minimum and maximum) Val width(void) const; //@} }; template inline Bounded::Bounded(I& i0, Val min0, bool umin0, Val max0, bool umax0) : i(i0), _min(min0), use_min(umin0), _max(max0), use_max(umax0) { while (i() && use_min && i.max() < _min) ++i; } template inline Bounded Bounded::miniter(I& i, Val min) { return Bounded(i,min,true,0,false); } template inline Bounded Bounded::maxiter(I& i, Val max) { return Bounded(i,0,false,max,true); } template inline Bounded Bounded::minmaxiter(I& i, Val min, Val max) { return Bounded(i,min,true,max,true); } template inline bool Bounded::operator ()(void) const { return i() && (!use_max || i.min() <= _max); } template inline void Bounded::operator ++(void) { ++i; while (i() && use_min && i.max() < _min) ++i; } template inline Val Bounded::min(void) const { return use_min ? std::max(_min,i.min()) : i.min(); } template inline Val Bounded::max(void) const { return use_max ? std::min(_max,i.max()) : i.max(); } template inline Val Bounded::width(void) const { if (min() > max()) return 0; if (min().isFinite() && max().isFinite()) return max()-min()+1; return Val::infinity(); } template class Const { protected: Val _min; Val _max; bool done; public: Const(Val min0, Val max0); /// \name Iteration control //@{ /// Test whether iterator is still at a range or done bool operator ()(void) const; /// Move iterator to next range (if possible) void operator ++(void); //@} /// \name Range access //@{ /// Return smallest value of range Val min(void) const; /// Return largest value of range Val max(void) const; /// Return width of range (distance between minimum and maximum) Val width(void) const; //@} }; template inline Const::Const(Val min0, Val max0) : _min(min0), _max(max0), done(min0>max0) {} template inline bool Const::operator ()(void) const { return !done; } template inline void Const::operator ++(void) { done = true; } template inline Val Const::min(void) const { return _min; } template inline Val Const::max(void) const { return _max; } template inline Val Const::width(void) const { if (min() > max()) return 0; if (min().isFinite() && max().isFinite()) return max()-min()+1; return Val::infinity(); } /** * \brief Range iterator for computing union (binary) * * \ingroup FuncIterRanges */ template class Union : public MinMax { protected: /// First iterator I i; /// Second iterator J j; public: /// \name Constructors and initialization //@{ /// Default constructor Union(void); /// Initialize with iterator \a i and \a j Union(I& i, J& j); /// Initialize with iterator \a i and \a j void init(I& i, J& j); //@} /// \name Iteration control //@{ /// Move iterator to next range (if possible) void operator ++(void); //@} }; /// Return whether an interval ending with \a x overlaps with an interval starting at \a y inline bool overlaps(const IntVal& x, const IntVal& y) { return x.plus(1) >= y; } /// Return whether an interval ending with \a x overlaps with an interval starting at \a y inline bool overlaps(const FloatVal& x, const FloatVal& y) { if (x.isPlusInfinity()) return true; if (y.isMinusInfinity()) return true; if (x.isFinite() && y.isFinite()) { return std::nextafter(x.toDouble(),INFINITY) >= y.toDouble(); } return x >= y; } inline IntVal nextHigher(const IntVal& x) { return x.plus(1); } inline IntVal nextLower(const IntVal& x) { return x.minus(1); } inline FloatVal nextHigher(const FloatVal& x) { if (x.isFinite()) return std::nextafter(x.toDouble(),INFINITY); return x; } inline FloatVal nextLower(const FloatVal& x) { if (x.isFinite()) return std::nextafter(x.toDouble(),-INFINITY); return x; } /* * Binary union * */ template inline void Union::operator ++(void) { if (!i() && !j()) { MinMax::finish(); return; } if (!i() || (j() && (!overlaps(j.max(),i.min())))) { MinMax::mi = j.min(); MinMax::ma = j.max(); ++j; return; } if (!j() || (i() && (!overlaps(i.max(),j.min())))) { MinMax::mi = i.min(); MinMax::ma = i.max(); ++i; return; } MinMax::mi = std::min(i.min(),j.min()); MinMax::ma = std::max(i.max(),j.max()); ++i; ++j; next: if (i() && (overlaps(MinMax::ma,i.min()))) { MinMax::ma = std::max(MinMax::ma,i.max()); ++i; goto next; } if (j() && (overlaps(MinMax::ma,j.min()))) { MinMax::ma = std::max(MinMax::ma,j.max()); ++j; goto next; } } template inline Union::Union(void) {} template inline Union::Union(I& i0, J& j0) : i(i0), j(j0) { operator ++(); } template inline void Union::init(I& i0, J& j0) { i = i0; j = j0; operator ++(); } /** * \brief Range iterator for computing intersection (binary) * * \ingroup FuncIterRanges */ template class Inter : public MinMax { protected: /// First iterator I i; /// Second iterator J j; public: /// \name Constructors and initialization //@{ /// Default constructor Inter(void); /// Initialize with iterator \a i and \a j Inter(I& i, J& j); /// Initialize with iterator \a i and \a j void init(I& i, J& j); //@} /// \name Iteration control //@{ /// Move iterator to next range (if possible) void operator ++(void); //@} }; /* * Binary intersection * */ template inline void Inter::operator ++(void) { if (!i() || !j()) goto done; do { while (i() && (i.max() < j.min())) ++i; if (!i()) goto done; while (j() && (j.max() < i.min())) ++j; if (!j()) goto done; } while (i.max() < j.min()); // Now the intervals overlap: consume the smaller interval MinMax::ma = std::min(i.max(),j.max()); MinMax::mi = std::max(i.min(),j.min()); if (i.max() < j.max()) ++i; else ++j; return; done: MinMax::finish(); } template inline Inter::Inter(void) {} template inline Inter::Inter(I& i0, J& j0) : i(i0), j(j0) { operator ++(); } template inline void Inter::init(I& i0, J& j0) { i = i0; j = j0; operator ++(); } /** * \brief Range iterator for computing set difference * * \ingroup FuncIterRanges */ template class Diff : public MinMax { protected: /// Iterator from which to subtract I i; /// Iterator to be subtracted J j; public: /// \name Constructors and initialization //@{ /// Default constructor Diff(void); /// Initialize with iterator \a i and \a j Diff(I& i, J& j); /// Initialize with iterator \a i and \a j void init(I& i, J& j); //@} /// \name Iteration control //@{ /// Move iterator to next range (if possible) void operator ++(void); //@} }; template inline void Diff::operator ++(void) { // Precondition: mi <= ma // Task: find next mi greater than ma while (true) { if (!i()) break; bool isInfinite = (!MinMax::ma.isFinite() && MinMax::ma>0); MinMax::mi = nextHigher(MinMax::ma); MinMax::ma = i.max(); if (isInfinite || MinMax::mi > i.max()) { ++i; if (!i()) break; MinMax::mi = i.min(); MinMax::ma = i.max(); } while (j() && (j.max() < MinMax::mi)) ++j; if (j() && (j.min() <= MinMax::ma)) { // Now the interval [mi ... ma] must be shrunken // Is [mi ... ma] completely consumed? if ((MinMax::mi >= j.min()) && (MinMax::ma <= j.max())) continue; // Does [mi ... ma] overlap on the left? if (j.min() <= MinMax::mi) { MinMax::mi = nextHigher(j.max()); // Search for max! ++j; if (j() && (j.min() <= MinMax::ma)) MinMax::ma = nextLower(j.min()); } else { MinMax::ma = nextLower(j.min()); } } return; } MinMax::finish(); } template inline Diff::Diff(void) {} template inline Diff::Diff(I& i0, J& j0) : i(i0), j(j0) { if (!i()) { MinMax::finish(); } else { MinMax::mi = nextLower(i.min()); MinMax::ma = MinMax::mi; operator ++(); } } template inline void Diff::init(I& i0, J& j0) { i = i0; j = j0; if (!i()) { MinMax::finish(); } else { MinMax::mi = nextLower(i.min()); MinMax::ma = MinMax::mi; operator ++(); } } /** * \brief Value iterator from range iterator * * \ingroup FuncIterValues */ template class ToValues { protected: /// Range iterator used I i; /// Current value IntVal cur; /// End of current range IntVal max; /// Initialize iterator void start(void); public: /// \name Constructors and initialization //@{ /// Default constructor ToValues(void); /// Initialize with values from range iterator \a i ToValues(I& i); /// Initialize with values from range iterator \a i void init(I& i); //@} /// \name Iteration control //@{ /// Test whether iterator is still at a value or done bool operator ()(void) const; /// Move iterator to next value (if possible) void operator ++(void); //@} /// \name Value access //@{ /// Return current value IntVal val(void) const; //@} }; template inline ToValues::ToValues(void) {} template inline void ToValues::start(void) { if (i()) { cur = i.min(); max = i.max(); } else { cur = 1; max = 0; } } template inline ToValues::ToValues(I& i0) : i(i0) { start(); } template inline void ToValues::init(I& i0) { i = i0; start(); } template inline bool ToValues::operator ()(void) const { return (cur <= max); } template inline void ToValues::operator ++(void) { ++cur; if (cur > max) { ++i; if (i()) { cur = i.min(); max = i.max(); } } } template inline IntVal ToValues::val(void) const { return cur; } /** * \defgroup FuncIterRangesOp Operations on range iterators * * \ingroup FuncIterRanges */ //@{ /// Cardinality of the set represented by range iterator \a i template IntVal cardinality(I& i); /// Check whether range iterators \a i and \a j are equal template bool equal(I& i, J& j); /// Check whether range iterator \a i is subset of range iterator \a j template bool subset(I& i, J& j); /// Check whether range iterators \a i and \a j are disjoint template bool disjoint(I& i, J& j); /// Comapre two iterators with each other enum CompareStatus { CS_SUBSET, ///< First is subset of second iterator CS_DISJOINT, ///< Intersection is empty CS_NONE ///< Neither of the above }; /// Check whether range iterator \a i is a subset of \a j, or whether they are disjoint template CompareStatus compare(I& i, J& j); //@} template inline IntVal cardinality(I& i) { IntVal s = 0; while (i()) { if (i.width().isFinite()) { s += i.width(); ++i; } else { return IntVal::infinity(); } } return s; } template inline bool equal(I& i, J& j) { // Are i and j equal? while (i() && j()) if ((i.min() == j.min()) && (i.max() == j.max())) { ++i; ++j; } else { return false; } return !i() && !j(); } template inline bool subset(I& i, J& j) { // Is i subset of j? while (i() && j()) if (j.max() < i.min()) { ++j; } else if ((i.min() >= j.min()) && (i.max() <= j.max())) { ++i; } else { return false; } return !i(); } template inline bool disjoint(I& i, J& j) { // Are i and j disjoint? while (i() && j()) if (j.max() < i.min()) { ++j; } else if (i.max() < j.min()) { ++i; } else { return false; } return true; } template inline CompareStatus compare(I& i, J& j) { bool subset = true; bool disjoint = true; while (i() && j()) { if (j.max() < i.min()) { ++j; } else if (i.max() < j.min()) { ++i; subset = false; } else if ((i.min() >= j.min()) && (i.max() <= j.max())) { ++i; disjoint = false; } else if (i.max() <= j.max()) { ++i; disjoint = false; subset = false; } else if (j.max() <= i.max()) { ++j; disjoint = false; subset = false; } } if (i()) subset = false; if (subset) return CS_SUBSET; return disjoint ? CS_DISJOINT : CS_NONE; } template inline bool less(I& i, J& j) { while (i()) { if (!j()) return false; if (i.min() < j.min()) return true; if (i.min() > j.min()) return false; if (i.max() < j.max()) return true; if (i.max() > j.max()) return false; ++i; ++j; } if (j()) return true; return false; } template inline bool lessEq(I& i, J& j) { while (i()) { if (!j()) return false; if (i.min() < j.min()) return true; if (i.min() > j.min()) return false; if (i.max() < j.max()) return true; if (i.max() > j.max()) return false; ++i; ++j; } return true; } }} #endif libminizinc-2.4.2/include/minizinc/json_parser.hh000066400000000000000000000041051360574160400221450ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_JSON_PARSER_HH__ #define __MINIZINC_JSON_PARSER_HH__ #include #include #include #include #include namespace MiniZinc { class JSONError : public LocationException { public: JSONError(EnvI& env, const Location& loc, const std::string& msg) : LocationException(env,loc,msg) {} virtual const char* what(void) const throw() { return "MiniZinc: JSON parsing error"; } }; class JSONParser { protected: enum TokenT { T_LIST_OPEN, T_LIST_CLOSE, T_OBJ_OPEN, T_OBJ_CLOSE, T_COMMA, T_COLON, T_STRING, T_INT, T_FLOAT, T_BOOL, T_NULL, T_EOF } t; class Token; EnvI& env; int line; int column; std::string filename; Location errLocation(void) const; Token readToken(std::istream& is); void expectToken(std::istream& is, TokenT t); std::string expectString(std::istream& is); Token parseEnumString(std::istream& is); Expression* parseExp(std::istream& is); ArrayLit* parseArray(std::istream& is); Expression* parseObject(std::istream& is); void parse(Model*m, std::istream& is); public: JSONParser(EnvI& env0) : env(env0) {} /// Parses \a filename as MiniZinc data and creates assign items in \a m void parse(Model* m, const std::string& filename); /// Parses \a data as JSON-encoded MiniZinc data and creates assign items in \a m void parseFromString(Model* m, const std::string& data); /// Check if file \a filename may contain JSON-encoded MiniZinc data static bool fileIsJSON(const std::string& filename); /// Check if string \a data may contain JSON-encoded MiniZinc data static bool stringIsJSON(const std::string& data); }; } #endif libminizinc-2.4.2/include/minizinc/model.hh000066400000000000000000000316271360574160400207310ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_MODEL_HH__ #define __MINIZINC_MODEL_HH__ #include #include #include #include #include #include namespace MiniZinc { class VarDeclIterator; class ConstraintIterator; class FunctionIterator; class CopyMap; class EnvI; /// A MiniZinc model class Model { friend class GC; friend Model* copy(EnvI& env, CopyMap& cm, Model* m, bool isFlatModel); protected: /// Previous model in root set list Model* _roots_prev; /// Next model in root set list Model* _roots_next; public: struct FnEntry { std::vector t; FunctionI* fi; bool isPolymorphic; FnEntry(FunctionI* fi0); bool operator <(const FnEntry&) const; static bool compare(const FnEntry& e1, const FnEntry& e2); }; protected: /// Add all instances of polymorphic entry \a fe to \a entries void addPolymorphicInstances(Model::FnEntry& fe, std::vector& entries); /// Type of map from identifiers to function declarations typedef ASTStringMap >::t FnMap; /// Map from identifiers to function declarations FnMap fnmap; /// Type of map from Type (represented as int) to reverse mapper functions typedef std::unordered_map RevMapperMap; /// Map from Type (represented as int) to reverse mapper functions RevMapperMap revmapmap; /// Filename of the model ASTString _filename; /// Path of the model ASTString _filepath; /// Parent model if model was included Model* _parent; /// Items in the model std::vector _items; /// Pointer to the solve item SolveI* _solveItem; /// Pointer to the output item OutputI* _outputItem; /// File-level documentation comment std::string _docComment; /// Store some declarations struct FnDecls { using TCheckedDecl = std::pair; // bool means that it was checked TCheckedDecl bounds_disj={false, nullptr}; // SCIP's bound disjunction } fnDecls; public: /// Construct empty model Model(void); /// Destructor ~Model(void); /// Add \a i to the model void addItem(Item* i); /// Get parent model Model* parent(void) const { return _parent; } /// Set parent model to \a p void setParent(Model* p) { assert(_parent==NULL); _parent = p; } /// Get file name ASTString filename(void) const { return _filename; } /// Get file path ASTString filepath(void) const { return _filepath; } /// Set file name void setFilename(const std::string& f) { assert(_filename.size()==0); _filename = ASTString(f); } /// Set file path void setFilepath(const std::string& f) { assert(_filepath.size()==0); _filepath = ASTString(f); } /// Register a builtin function item void registerFn(EnvI& env, FunctionI* fi); /// Sort functions by type void sortFn(void); /// Check that registered functions do not clash wrt overloading void checkFnOverloading(EnvI& env); /// Fix function table after type checking void fixFnMap(void); /// Return function declaration for \a id matching \a args FunctionI* matchFn(EnvI& env, const ASTString& id, const std::vector& args, bool strictEnums) const; /// Return function declaration for \a id matching types \a t FunctionI* matchFn(EnvI& env, const ASTString& id, const std::vector& t, bool strictEnums); /// Return function declaration matching call \a c FunctionI* matchFn(EnvI& env, Call* c, bool strictEnums) const; /// Return function declaration for reverse mapper for type \a t FunctionI* matchRevMap(EnvI& env, const Type& t) const; /// Check whether functions \a f and \a g have the same overloaded variants bool sameOverloading(EnvI& env, const std::vector& args, FunctionI* f, FunctionI* g) const; /// Merge all builtin functions into \a m void mergeStdLib(EnvI& env, Model* m) const; /// Return item \a i Item*& operator[] (int i); /// Return item \a i const Item* operator[] (int i) const; /// Return number of items unsigned int size(void) const; typedef std::vector::iterator iterator; typedef std::vector::const_iterator const_iterator; /// Iterator for beginning of items iterator begin(void); /// Iterator for beginning of items const_iterator begin(void) const; /// Iterator for end of items iterator end(void); /// Iterator for end of items const_iterator end(void) const; ConstraintIterator begin_constraints(void); ConstraintIterator end_constraints(void); VarDeclIterator begin_vardecls(void); VarDeclIterator end_vardecls(void); FunctionIterator begin_functions(void); FunctionIterator end_functions(void); SolveI* solveItem(void); OutputI* outputItem(void); void setOutputItem(OutputI* oi); /// Add a file-level documentation comment void addDocComment(std::string s) { _docComment += s; } /// Return the file-level documentation comment const std::string& docComment(void) const { return _docComment; } /// Remove all items marked as removed void compact(void); /// Get the stored function declarations FnDecls& getFnDecls() { return fnDecls; } }; class VarDeclIterator { Model* _model; Model::iterator _it; public: typedef Model::iterator::difference_type difference_type; typedef Model::iterator::value_type value_type; typedef VarDeclI& reference; typedef VarDeclI* pointer; typedef std::forward_iterator_tag iterator_category; VarDeclIterator() {} VarDeclIterator(const VarDeclIterator& vi) : _it(vi._it) {} VarDeclIterator(Model* model, const Model::iterator& it) : _model(model), _it(it) { while (_it != _model->end() && (!(*_it)->isa() || (*_it)->removed())) { ++_it; } } ~VarDeclIterator() {} VarDeclIterator& operator=(const VarDeclIterator& vi) { if (this != &vi) { _it = vi._it; } return *this; } bool operator==(const VarDeclIterator& vi) const { return _it == vi._it; } bool operator!=(const VarDeclIterator& vi) const { return _it != vi._it; } VarDeclIterator& operator++() { do { ++_it; } while (_it != _model->end() && (!(*_it)->isa() || (*_it)->removed())); return *this; } reference operator*() const { return *(*_it)->cast(); } pointer operator->() const { return (*_it)->cast(); } }; class ConstraintIterator { Model* _model; Model::iterator _it; public: typedef Model::iterator::difference_type difference_type; typedef Model::iterator::value_type value_type; typedef ConstraintI& reference; typedef ConstraintI* pointer; typedef std::forward_iterator_tag iterator_category; ConstraintIterator() {} ConstraintIterator(const ConstraintIterator& vi) : _it(vi._it) {} ConstraintIterator(Model* model, const Model::iterator& it) : _model(model), _it(it) { while (_it != _model->end() && (!(*_it)->isa() || (*_it)->removed())) { ++_it; } } ~ConstraintIterator() {} ConstraintIterator& operator=(const ConstraintIterator& vi) { if (this != &vi) { _it = vi._it; } return *this; } bool operator==(const ConstraintIterator& vi) const { return _it == vi._it; } bool operator!=(const ConstraintIterator& vi) const { return _it != vi._it; } ConstraintIterator& operator++() { do { ++_it; } while (_it != _model->end() && (!(*_it)->isa() || (*_it)->removed())); return *this; } reference operator*() const { return *(*_it)->cast(); } pointer operator->() const { return (*_it)->cast(); } }; class FunctionIterator { Model* _model; Model::iterator _it; public: typedef Model::iterator::difference_type difference_type; typedef Model::iterator::value_type value_type; typedef FunctionI& reference; typedef FunctionI* pointer; typedef std::forward_iterator_tag iterator_category; FunctionIterator() {} FunctionIterator(const FunctionIterator& vi) : _it(vi._it) {} FunctionIterator(Model* model, const Model::iterator& it) : _model(model), _it(it) { while (_it != _model->end() && (!(*_it)->isa() || (*_it)->removed())) { ++_it; } } ~FunctionIterator() {} FunctionIterator& operator=(const FunctionIterator& vi) { if (this != &vi) { _it = vi._it; } return *this; } bool operator==(const FunctionIterator& vi) const { return _it == vi._it; } bool operator!=(const FunctionIterator& vi) const { return _it != vi._it; } FunctionIterator& operator++() { do { ++_it; } while (_it != _model->end() && (!(*_it)->isa() || (*_it)->removed())); return *this; } reference operator*() const { return *(*_it)->cast(); } pointer operator->() const { return (*_it)->cast(); } }; class EnvI; /// Environment class Env { private: EnvI* e; public: Env(Model* m=NULL, std::ostream& outstream = std::cout, std::ostream& errstream = std::cerr); ~Env(void); Model* model(void); void model(Model* m); Model* flat(void); void swap(); Model* output(void); EnvI& envi(void); const EnvI& envi(void) const; std::ostream& dumpErrorStack(std::ostream& os); const std::vector& warnings(void); void clearWarnings(void); unsigned int maxCallStack(void) const; std::ostream& evalOutput(std::ostream& os); }; class CallStackItem { public: EnvI& env; CallStackItem(EnvI& env0, Expression* e); CallStackItem(EnvI& env0, Id* ident, IntVal i); ~CallStackItem(void); }; /// Visitor for model items class ItemVisitor { public: /// Enter model bool enterModel(Model* m) { return true; } /// Enter item bool enter(Item* m) { return true; } /// Visit include item void vIncludeI(IncludeI*) {} /// Visit variable declaration void vVarDeclI(VarDeclI*) {} /// Visit assign item void vAssignI(AssignI*) {} /// Visit constraint item void vConstraintI(ConstraintI*) {} /// Visit solve item void vSolveI(SolveI*) {} /// Visit output item void vOutputI(OutputI*) {} /// Visit function item void vFunctionI(FunctionI*) {} }; /// Iterator over items in a model and all its included models template class ItemIter { protected: I& iter; public: ItemIter(I& iter0) : iter(iter0) {} void run(Model* m) { std::unordered_set seen; std::vector models; models.push_back(m); seen.insert(m); while (!models.empty()) { Model* cm = models.back(); models.pop_back(); if (!iter.enterModel(cm)) continue; std::vector includedModels; for (unsigned int i=0; isize(); i++) { if ((*cm)[i]->removed()) continue; if (!iter.enter((*cm)[i])) continue; switch ((*cm)[i]->iid()) { case Item::II_INC: if (seen.find((*cm)[i]->cast()->m()) == seen.end()) { includedModels.push_back((*cm)[i]->cast()->m()); seen.insert((*cm)[i]->cast()->m()); } iter.vIncludeI((*cm)[i]->cast()); break; case Item::II_VD: iter.vVarDeclI((*cm)[i]->cast()); break; case Item::II_ASN: iter.vAssignI((*cm)[i]->cast()); break; case Item::II_CON: iter.vConstraintI((*cm)[i]->cast()); break; case Item::II_SOL: iter.vSolveI((*cm)[i]->cast()); break; case Item::II_OUT: iter.vOutputI((*cm)[i]->cast()); break; case Item::II_FUN: iter.vFunctionI((*cm)[i]->cast()); break; } } for (unsigned int i=static_cast(includedModels.size()); i--;) { models.push_back(includedModels[i]); } } } }; /// Run iterator \a i over all items of model \a m template void iterItems(I& i, Model* m) { ItemIter(i).run(m); } } #endif libminizinc-2.4.2/include/minizinc/optimize.hh000066400000000000000000000063371360574160400214710ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_OPTIMIZE_HH__ #define __MINIZINC_OPTIMIZE_HH__ #include #include namespace MiniZinc { class VarOccurrences { public: typedef std::unordered_set Items; IdMap _m; IdMap idx; /// Add \a to the index void add_idx(VarDeclI* i, int idx_i); /// Add \a to the index void add_idx(VarDecl* e, int idx_i); /// Find index of \a vd int find(VarDecl* vd); /// Remove index of \a vd void remove(VarDecl* vd); /// Add \a i to the dependencies of \a v void add(VarDecl* v, Item* i); /// Remove \a i from map and return new number of occurrences int remove(VarDecl* v, Item* i); /// Remove all occurrences from map and return new number of occurrences void removeAllOccurrences(VarDecl* v); /// Return number of occurrences of \a v int occurrences(VarDecl* v); /// Return number of constraint usages of \a v and whether \a v is an output variable std::pair usages(VarDecl* v); /// Unify \a v0 and \a v1 (removing \a v0) void unify(EnvI& env, Model* m, Id* id0, Id* id1); /// Clear all entries void clear(void); }; class CollectOccurrencesE : public EVisitor { public: VarOccurrences& vo; Item* ci; CollectOccurrencesE(VarOccurrences& vo0, Item* ci0) : vo(vo0), ci(ci0) {} void vId(const Id& id) { if(id.decl()) vo.add(id.decl(),ci); } }; class CollectOccurrencesI : public ItemVisitor { public: VarOccurrences& vo; CollectOccurrencesI(VarOccurrences& vo0) : vo(vo0) {} void vVarDeclI(VarDeclI* v); void vConstraintI(ConstraintI* ci); void vSolveI(SolveI* si); }; class CollectDecls : public EVisitor { public: VarOccurrences& vo; std::vector& vd; Item* item; CollectDecls(VarOccurrences& vo0, std::vector& vd0, Item* item0) : vo(vo0), vd(vd0), item(item0) {} static bool varIsFree(VarDecl* vd) { if (vd->e()==NULL || vd->ti()->domain()==NULL || vd->ti()->computedDomain()) { return true; } else { /// TODO: test if id's domain is a superset of the right hand side /// this currently only tests for equality, and for Boolean domains if (Id* ident = vd->e()->dyn_cast()) { if (Expression::equal(ident->decl()->ti()->domain(), vd->ti()->domain())) { return true; } } else if (vd->e()==vd->ti()->domain()) { return true; } } return false; } void vId(Id& id) { if (id.decl() && vo.remove(id.decl(),item) == 0) { if (varIsFree(id.decl())) { vd.push_back(id.decl()); } } } }; bool isOutput(VarDecl* vd); /// Simplyfy models in \a env void optimize(Env& env, bool chain_compression = true); } #endif libminizinc-2.4.2/include/minizinc/optimize_constraints.hh000066400000000000000000000017501360574160400241120ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_OPTIMIZE_CONSTRAINTS_HH__ #define __MINIZINC_OPTIMIZE_CONSTRAINTS_HH__ #include #include namespace MiniZinc { class OptimizeRegistry { public: enum ConstraintStatus { CS_NONE, CS_OK, CS_FAILED, CS_ENTAILED, CS_REWRITE }; typedef ConstraintStatus (*optimizer) (EnvI& env, Item* i, Call* c, Expression*& rewrite); protected: ASTStringMap::t _m; public: void reg(const ASTString& call, optimizer); ConstraintStatus process(EnvI& env, Item* i, Call* c, Expression*& rewrite); static OptimizeRegistry& registry(void); }; } #endif libminizinc-2.4.2/include/minizinc/options.hh000066400000000000000000000033771360574160400213250ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_OPTIONS_HH__ #define __MINIZINC_OPTIONS_HH__ #include namespace MiniZinc { class Options { protected: std::unordered_map _options; Expression* getParam(const std::string& name) const; public: void setIntParam(const std::string& name, KeepAlive e); void setFloatParam(const std::string& name, KeepAlive e); void setBoolParam(const std::string& name, KeepAlive e); void setStringParam(const std::string& name, KeepAlive e); void setIntParam(const std::string& name, long long int e); void setFloatParam(const std::string& name, double e); void setBoolParam(const std::string& name, bool e); void setStringParam(const std::string& name, std::string e); long long int getIntParam(const std::string& name) const; long long int getIntParam(const std::string& name, long long int def) const; double getFloatParam(const std::string& name) const; double getFloatParam(const std::string& name, double def) const; bool getBoolParam(const std::string& name) const; bool getBoolParam(const std::string& name, bool def) const; std::string getStringParam(const std::string& name) const; std::string getStringParam(const std::string& name, std::string def) const; bool hasParam(const std::string& name) const; std::ostream& dump(std::ostream& os); }; } #endif libminizinc-2.4.2/include/minizinc/output.hh000066400000000000000000000024221360574160400211600ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_OUTPUT_HH__ #define __MINIZINC_OUTPUT_HH__ #include namespace MiniZinc { /// Remove all output annotations from \a vd void removeIsOutput(VarDecl* vd); /// Copy output item to FlatZinc model void copyOutput(EnvI& e); /// Copy all dependent variable declarations void outputVarDecls(EnvI& env, Item* ci, Expression* e); /// Create initial output model void createOutput(EnvI& e, std::vector& deletedFlatVarDecls, FlatteningOptions::OutputMode outputMode, bool outputObjective, bool includeOutputItem); /// Finalise output model after flattening is complete void finaliseOutput(EnvI& e, std::vector& deletedFlatVarDecls); /// Remove all links to variables in flat model from output model in \a env void cleanupOutput(EnvI& env); ArrayLit* createJSONOutput(EnvI& env, bool outputObjective, bool includeOutputItem); } #endif libminizinc-2.4.2/include/minizinc/parser.hh000066400000000000000000000107431360574160400211210ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_PARSER_HH__ #define __MINIZINC_PARSER_HH__ // This is a workaround for a bug in flex that only shows up // with the Microsoft C++ compiler #if defined(_MSC_VER) #define YY_NO_UNISTD_H #ifdef __cplusplus extern "C" int isatty(int); #endif #endif // The Microsoft C++ compiler marks certain functions as deprecated, // so let's take the alternative definitions #if defined(_MSC_VER) #define strdup _strdup #define fileno _fileno #endif #if defined(_MSC_VER) #pragma warning(disable:4065) #endif #include #include #include #include #include #include #include #include #include #include #include namespace MiniZinc { struct ParseWorkItem { Model* m; IncludeI* ii; std::string dirName; std::string fileName; bool isModelString; ParseWorkItem(Model* m0, IncludeI* ii0, const std::string& dirName0, const std::string& fileName0, bool isModelString0=false) : m(m0), ii(ii0), dirName(dirName0), fileName(fileName0), isModelString(isModelString0) {} }; /// %State of the %MiniZinc parser class ParserState { public: ParserState(const std::string& f, const std::string& b, std::ostream& err0, std::vector& files0, std::map& seenModels0, MiniZinc::Model* model0, bool isDatafile0, bool isFlatZinc0, bool parseDocComments0) : filename(f.c_str()), buf(b.c_str()), pos(0), length(static_cast(b.size())), lineStartPos(0), nTokenNextStart(1), hadNewline(false), files(files0), seenModels(seenModels0), model(model0), isDatafile(isDatafile0), isFlatZinc(isFlatZinc0), parseDocComments(parseDocComments0), hadError(false), err(err0) {} const char* filename; void* yyscanner; const char* buf; unsigned int pos, length; int lineStartPos; int nTokenNextStart; bool hadNewline; std::vector& files; std::map& seenModels; MiniZinc::Model* model; bool isDatafile; bool isFlatZinc; bool parseDocComments; bool hadError; std::vector syntaxErrors; std::ostream& err; std::string stringBuffer; void printCurrentLine(int firstCol, int lastCol) { const char* eol_c = strchr(buf+lineStartPos,'\n'); if (eol_c) { if (eol_c==buf+lineStartPos) return; err << std::string(buf+lineStartPos,eol_c-(buf+lineStartPos)); } else { err << buf+lineStartPos; } err << std::endl; for (int i=0; i= length) return 0; int num = std::min(length - pos, lexBufSize); memcpy(lexBuf,buf+pos,num); pos += num; return num; } }; Model* parse(Env& env, const std::vector& filename, const std::vector& datafiles, const std::string& textModel, const std::string& textModelName, const std::vector& includePaths, bool ignoreStdlib, bool parseDocComments, bool verbose, std::ostream& err); Model* parseFromString(Env& env, const std::string& model, const std::string& filename, const std::vector& includePaths, bool ignoreStdlib, bool parseDocComments, bool verbose, std::ostream& err, std::vector& syntaxErrors); Model* parseData(Env& env, Model* m, const std::vector& datafiles, const std::vector& includePaths, bool ignoreStdlib, bool parseDocComments, bool verbose, std::ostream& err); } #endif libminizinc-2.4.2/include/minizinc/passes/000077500000000000000000000000001360574160400205755ustar00rootroot00000000000000libminizinc-2.4.2/include/minizinc/passes/compile_pass.hh000066400000000000000000000025251360574160400236000ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Kevin Leo */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_COMPILE_PASS_HH__ #define __MINIZINC_COMPILE_PASS_HH__ #include #include namespace MiniZinc { struct CompilePassFlags { bool noMIPdomains; bool verbose; bool statistics; bool optimize; bool chain_compression; bool newfzn; bool werror; bool model_check_only; bool model_interface_only; bool allow_multi_assign; }; class CompilePass : public Pass { private: Env* env; FlatteningOptions fopts; CompilePassFlags compflags; std::string library; std::vector includePaths; bool change_library; bool ignore_unknown_ids; public: CompilePass(Env* e, FlatteningOptions& opts, CompilePassFlags& cflags, std::string globals_library, std::vector include_paths, bool change_lib, bool ignore_unknown); Env* run(Env* env, std::ostream& log); ~CompilePass(); }; } #endif libminizinc-2.4.2/include/minizinc/passes/gecode_pass.hh000066400000000000000000000012301360574160400233660ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Kevin Leo */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_GECODE_PASS_HH__ #define __MINIZINC_GECODE_PASS_HH__ #include namespace MiniZinc { class GecodeOptions; class GecodePass : public Pass { GecodeOptions* gopts; public: GecodePass(GecodeOptions* gopts); Env* run(Env* e, std::ostream& log); }; } #endif libminizinc-2.4.2/include/minizinc/pathfileprinter.hh000066400000000000000000000016501360574160400230220ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_PATHPRINTER_HH #define __MINIZINC_PATHPRINTER_HH #include #include namespace MiniZinc { class Model; class PathFilePrinter { typedef std::pair NamePair; typedef std::unordered_map NameMap; NameMap betternames; private: std::ostream& os; int constraint_index; void addBetterName(Id* id, std::string name, std::string path, bool overwrite); public: PathFilePrinter(std::ostream& o, EnvI& envi); void print(Model* m); void print(Item* i); }; } #endif libminizinc-2.4.2/include/minizinc/prettyprinter.hh000066400000000000000000000037511360574160400225610ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Pierre Wilke * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_PRETTYPRINTER_HH__ #define __MINIZINC_PRETTYPRINTER_HH__ #include #include namespace MiniZinc { class Document; class ItemDocumentMapper; class PrettyPrinter; class Printer { private: EnvI* env; ItemDocumentMapper* ism; PrettyPrinter* printer; std::ostream& _os; int _width; bool _flatZinc; void init(void); void p(Document* d); void p(const Item* i); public: Printer(std::ostream& os, int width=80, bool flatZinc=true, EnvI* env=NULL); ~Printer(void); void print(const Expression* e); void print(const Item* i); void print(const Model* m); static std::string escapeStringLit(const ASTString& s); }; /// Output operator for expressions template std::basic_ostream& operator <<(std::basic_ostream& os, const Expression& e) { std::basic_ostringstream s; s.copyfmt(os); s.width(0); Printer p(s,0); p.print(&e); return os << s.str(); } /// Output operator for items template std::basic_ostream& operator <<(std::basic_ostream& os, const Item& i) { std::basic_ostringstream s; s.copyfmt(os); s.width(0); Printer p(s); p.print(&i); return os << s.str(); } void ppFloatVal(std::ostream& os, const FloatVal& fv, bool hexFloat=false); } void debugprint(MiniZinc::Expression* e); void debugprint(MiniZinc::Item* i); void debugprint(MiniZinc::Model* m); void debugprint(const MiniZinc::Location& l); #endif libminizinc-2.4.2/include/minizinc/process.hh000066400000000000000000000332121360574160400212770ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_PROCESS_HH__ #define __MINIZINC_PROCESS_HH__ #include const auto SolverInstance__ERROR = MiniZinc::SolverInstance::ERROR; // before windows.h #ifdef _WIN32 #define NOMINMAX #include #include //#include #else #include #include #include #include #endif #include #include #include #include #include #include #include #include namespace MiniZinc { #ifdef _WIN32 template void ReadPipePrint(HANDLE g_hCh, bool* _done, std::ostream* pOs, std::deque* outputQueue, std::mutex* mtx, std::mutex* cv_mutex, std::condition_variable* cv) { bool& done = *_done; assert(pOs != 0 || outputQueue != 0); while (!done) { char buffer[5255]; char nl_buffer[5255]; DWORD count = 0; BOOL bSuccess = ReadFile(g_hCh, buffer, sizeof(buffer) - 1, &count, NULL); if (bSuccess && count > 0) { int nl_count = 0; for (int i = 0; i < count; i++) { if (buffer[i] != 13) { nl_buffer[nl_count++] = buffer[i]; } } nl_buffer[nl_count] = 0; std::lock_guard lck(*mtx); if (outputQueue) { std::unique_lock lk(*cv_mutex); bool wasEmpty = outputQueue->empty(); outputQueue->push_back(nl_buffer); lk.unlock(); if (wasEmpty) { cv->notify_one(); } } if (pOs) (*pOs) << nl_buffer << std::flush; } else { if (outputQueue) { std::unique_lock lk(*cv_mutex); bool wasEmpty = outputQueue->empty(); outputQueue->push_back("\n"); done = true; lk.unlock(); if (wasEmpty) { cv->notify_one(); } } else { done = true; } } } } void TimeOut(HANDLE hProcess, bool* doneStdout, bool* doneStderr, int timeout, std::timed_mutex* mtx); #endif template class Process { protected: std::vector _fzncmd; S2O* pS2Out; int timelimit; bool sigint; #ifndef _WIN32 static void handleInterrupt(int signal) { if (signal==SIGINT) hadInterrupt = true; else hadTerm = true; } static bool hadInterrupt; static bool hadTerm; #endif public: Process(std::vector& fzncmd, S2O* pso, int tl, bool si) : _fzncmd(fzncmd), pS2Out(pso), timelimit(tl), sigint(si) { assert( 0!=pS2Out ); } int run(void) { #ifdef _WIN32 //TODO: implement hard timelimits for windows SECURITY_ATTRIBUTES saAttr; saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; HANDLE g_hChildStd_IN_Rd = NULL; HANDLE g_hChildStd_IN_Wr = NULL; HANDLE g_hChildStd_OUT_Rd = NULL; HANDLE g_hChildStd_OUT_Wr = NULL; HANDLE g_hChildStd_ERR_Rd = NULL; HANDLE g_hChildStd_ERR_Wr = NULL; // Create a pipe for the child process's STDOUT. if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) std::cerr << "Stdout CreatePipe" << std::endl; // Ensure the read handle to the pipe for STDOUT is not inherited. if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) std::cerr << "Stdout SetHandleInformation" << std::endl; // Create a pipe for the child process's STDERR. if (!CreatePipe(&g_hChildStd_ERR_Rd, &g_hChildStd_ERR_Wr, &saAttr, 0)) std::cerr << "Stderr CreatePipe" << std::endl; // Ensure the read handle to the pipe for STDERR is not inherited. if (!SetHandleInformation(g_hChildStd_ERR_Rd, HANDLE_FLAG_INHERIT, 0)) std::cerr << "Stderr SetHandleInformation" << std::endl; // Create a pipe for the child process's STDIN if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) std::cerr << "Stdin CreatePipe" << std::endl; // Ensure the write handle to the pipe for STDIN is not inherited. if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0)) std::cerr << "Stdin SetHandleInformation" << std::endl; PROCESS_INFORMATION piProcInfo; STARTUPINFO siStartInfo; BOOL bSuccess = FALSE; // Set up members of the PROCESS_INFORMATION structure. ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); // Set up members of the STARTUPINFO structure. // This structure specifies the STDIN and STDOUT handles for redirection. ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.hStdError = g_hChildStd_ERR_Wr; siStartInfo.hStdOutput = g_hChildStd_OUT_Wr; siStartInfo.hStdInput = g_hChildStd_IN_Rd; siStartInfo.dwFlags |= STARTF_USESTDHANDLES; std::string cmdline = FileUtils::combineCmdLine(_fzncmd); char* cmdstr = strdup(cmdline.c_str()); BOOL processStarted = CreateProcess(NULL, cmdstr, // command line NULL, // process security attributes NULL, // primary thread security attributes TRUE, // handles are inherited 0, // creation flags NULL, // use parent's environment NULL, // use parent's current directory &siStartInfo, // STARTUPINFO pointer &piProcInfo); // receives PROCESS_INFORMATION if (!processStarted) { std::stringstream ssm; ssm << "Error occurred when executing FZN solver with command \"" << cmdstr << "\"."; throw InternalError(ssm.str()); } CloseHandle(piProcInfo.hThread); delete cmdstr; // Stop ReadFile from blocking CloseHandle(g_hChildStd_OUT_Wr); CloseHandle(g_hChildStd_ERR_Wr); // Just close the child's in pipe here CloseHandle(g_hChildStd_IN_Rd); bool doneStdout = false; bool doneStderr = false; // Threaded solution seems simpler than asyncronous pipe reading std::mutex pipeMutex; std::timed_mutex terminateMutex; std::mutex cv_mutex; std::condition_variable cv; std::deque outputQueue; terminateMutex.lock(); thread thrStdout(&ReadPipePrint, g_hChildStd_OUT_Rd, &doneStdout, nullptr, &outputQueue, &pipeMutex, &cv_mutex, &cv); thread thrStderr(&ReadPipePrint, g_hChildStd_ERR_Rd, &doneStderr, &pS2Out->getLog(), nullptr, &pipeMutex, nullptr, nullptr); thread thrTimeout(TimeOut, piProcInfo.hProcess, &doneStdout, &doneStderr, timelimit, &terminateMutex); while (true) { std::unique_lock lk(cv_mutex); cv.wait(lk, [&] { return !outputQueue.empty(); }); while (!outputQueue.empty()) { try { pS2Out->feedRawDataChunk(outputQueue.front().c_str()); outputQueue.pop_front(); } catch (...) { TerminateProcess(piProcInfo.hProcess, 0); doneStdout = true; doneStderr = true; lk.unlock(); thrStdout.join(); thrStderr.join(); terminateMutex.unlock(); thrTimeout.join(); std::rethrow_exception(std::current_exception()); } } if (doneStdout) break; } thrStdout.join(); thrStderr.join(); terminateMutex.unlock(); thrTimeout.join(); DWORD exitCode = 0; if (GetExitCodeProcess(piProcInfo.hProcess, &exitCode) == FALSE) { exitCode = 1; } CloseHandle(piProcInfo.hProcess); // Hard timeout: GenerateConsoleCtrlEvent() return exitCode; } #else int pipes[3][2]; pipe(pipes[0]); pipe(pipes[1]); pipe(pipes[2]); if (int childPID = fork()) { close(pipes[0][0]); close(pipes[1][1]); close(pipes[2][1]); close(pipes[0][1]); fd_set fdset; FD_ZERO(&fdset); struct timeval starttime; gettimeofday(&starttime, NULL); struct timeval timeout_orig; timeout_orig.tv_sec = timelimit / 1000; timeout_orig.tv_usec = (timelimit % 1000) * 1000; struct timeval timeout = timeout_orig; hadInterrupt = false; hadTerm = false; struct sigaction sa; struct sigaction old_sa_int; struct sigaction old_sa_term; sa.sa_handler = &handleInterrupt; sa.sa_flags = 0; sigfillset(&sa.sa_mask); sigaction(SIGINT, &sa, &old_sa_int); sigaction(SIGTERM, &sa, &old_sa_term); bool done = hadTerm || hadInterrupt; bool timed_out = false; while (!done) { FD_SET(pipes[1][0], &fdset); FD_SET(pipes[2][0], &fdset); int sel = select(FD_SETSIZE, &fdset, NULL, NULL, timelimit==0 ? NULL : &timeout); if (sel==-1) { if (errno != EINTR) { // some error has happened throw InternalError(std::string("Error in communication with solver: ")+strerror(errno)); } } if (timelimit!=0) { timeval currentTime; gettimeofday(¤tTime, NULL); if (sel != 0) { timeval elapsed; elapsed.tv_sec = currentTime.tv_sec - starttime.tv_sec; elapsed.tv_usec = currentTime.tv_usec - starttime.tv_usec; if(elapsed.tv_usec < 0) { elapsed.tv_sec--; elapsed.tv_usec += 1000000; } // Reset timeout to original limit timeout = timeout_orig; // Subtract elapsed time timeout.tv_usec = timeout.tv_usec - elapsed.tv_usec; if (timeout.tv_usec < 0) { timeout.tv_sec--; timeout.tv_usec += 1000000; } timeout.tv_sec = timeout.tv_sec - elapsed.tv_sec; } else { timeout.tv_usec = 0; timeout.tv_sec = 0; } if(hadTerm || hadInterrupt || timeout.tv_sec < 0 || (timeout.tv_sec==0 && timeout.tv_usec == 0)) { timed_out = true; if(sigint) { kill(childPID, SIGINT); timeout.tv_sec = 0; timeout.tv_usec = 200000; timeout_orig = timeout; starttime = currentTime; sigint = false; } else { kill(childPID, SIGTERM); pS2Out->feedRawDataChunk( "\n" ); // in case last chunk did not end with \n done = true; } } } for ( int i=1; i<=2; ++i ) { if ( FD_ISSET( pipes[i][0], &fdset ) ) { char buffer[1000]; int count = read(pipes[i][0], buffer, sizeof(buffer) - 1); if (count > 0) { buffer[count] = 0; if ( 1==i ) { // cerr << "mzn-fzn: raw chunk stdout::: " << flush; // cerr << buffer << flush; pS2Out->feedRawDataChunk( buffer ); } else { pS2Out->getLog() << buffer << std::flush; } } else if ( 1==i ) { pS2Out->feedRawDataChunk("\n"); // in case last chunk did not end with \n done = true; } } } } close(pipes[1][0]); close(pipes[2][0]); int exitStatus = timed_out ? 0 : 1; int childStatus; int pidStatus = waitpid(childPID, &childStatus, 0); if (!timed_out && pidStatus > 0) { if (WIFEXITED(childStatus)) { exitStatus = WEXITSTATUS(childStatus); } } sigaction(SIGINT, &old_sa_int, NULL); sigaction(SIGTERM, &old_sa_term, NULL); if (hadInterrupt) { kill(getpid(), SIGINT); } if (hadTerm) { kill(getpid(), SIGTERM); } return exitStatus; } else { close(STDOUT_FILENO); close(STDERR_FILENO); close(STDIN_FILENO); dup2(pipes[0][0], STDIN_FILENO); dup2(pipes[1][1], STDOUT_FILENO); dup2(pipes[2][1], STDERR_FILENO); close(pipes[0][0]); close(pipes[0][1]); close(pipes[1][1]); close(pipes[1][0]); close(pipes[2][1]); close(pipes[2][0]); std::vector cmd_line; for (auto& iCmdl: _fzncmd) { cmd_line.push_back( strdup (iCmdl.c_str())); } char** argv = new char*[cmd_line.size() + 1]; for (unsigned int i = 0; i < cmd_line.size(); i++) argv[i] = cmd_line[i]; argv[cmd_line.size()] = 0; int status = execvp(argv[0], argv); // execvp only returns if an error occurs. assert(status == -1); // the returned value will always be -1 std::stringstream ssm; ssm << "Error occurred when executing FZN solver with command \""; for ( auto& s: cmd_line ) ssm << s << ' '; ssm << "\"."; throw InternalError(ssm.str()); } } #endif }; #ifndef _WIN32 template bool Process::hadInterrupt; template bool Process::hadTerm; #endif } #endif libminizinc-2.4.2/include/minizinc/solns2out.hh000066400000000000000000000144251360574160400215760ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_SOLNS2OUT_H__ #define __MINIZINC_SOLNS2OUT_H__ #include #include #include #include #include #include #include #include #include #include #include #include #include // temp., TODO #include #include #include #include #include namespace MiniZinc { /// Class handling fzn solver's output /// could facilitate exhange of raw/final outputs in a portfolio class Solns2Out { protected: std::unique_ptr pEnv_guard; Env* pEnv=0; Model* pOutput=0; typedef std::pair DE; std::unordered_map declmap; Expression* outputExpr = NULL; std::string checkerModel; bool fNewSol2Print = false; // should be set for evalOutput to work public: std::string solution; std::string comments; int nLinesIgnore = 0; struct Options { std::string flag_output_file; bool flag_output_comments = true; bool flag_output_flush = true; bool flag_output_time = false; int flag_ignore_lines = 0; bool flag_unique = 1; bool flag_canonicalize = 0; bool flag_standaloneSolns2Out = false; std::string flag_output_noncanonical; std::string flag_output_raw; int flag_number_output = -1; /// Default values, also used for input const char* const solution_separator_00 = "----------"; const char* const unsatisfiable_msg_00 = "=====UNSATISFIABLE====="; const char* const unbounded_msg_00 = "=====UNBOUNDED====="; const char* const unsatorunbnd_msg_00 = "=====UNSATorUNBOUNDED====="; const char* const unknown_msg_00 = "=====UNKNOWN====="; const char* const error_msg_00 = "=====ERROR====="; const char* const search_complete_msg_00= "=========="; /// Output values std::string solution_separator = solution_separator_00; std::string solution_comma = ""; std::string unsatisfiable_msg = unsatisfiable_msg_00; std::string unbounded_msg = unbounded_msg_00; std::string unsatorunbnd_msg = unsatorunbnd_msg_00; std::string unknown_msg = unknown_msg_00; std::string error_msg = error_msg_00; std::string search_complete_msg= search_complete_msg_00; } _opt; public: ~Solns2Out(); Solns2Out(std::ostream& os, std::ostream& log, const std::string& stdlibDir); bool processOption(int& i, std::vector& argv); void printHelp(std::ostream& ); /// The output model (~.ozn) can be passed in 1 way in this base class: /// passing Env* containing output() bool initFromEnv(Env* pE); /// Then, variable assignments can be passed either as text /// or put directly into envi()->output() ( latter done externally /// by e.g. SolverInstance::assignSolutionToOutput() ) /// In the 1st case, (part of) the assignment text is passed as follows, /// original end-of-lines need to be there as well bool feedRawDataChunk( const char* ); SolverInstance::Status status = SolverInstance::UNKNOWN; bool fStatusPrinted = false; /// Should be called when entering new solution into the output model. /// Default assignSolutionToOutput() does it by using findOutputVar(). void declNewOutput(); /// This can be used by assignSolutionToOutput() DE& findOutputVar( ASTString ); /// In the other case, /// the evaluation procedures print output/status to os /// returning false means need to stop (error/ too many solutions) /// Solution validation here TODO /// Note that --canonicalize delays output /// until ... exit, eof, ?? TODO /// These functions should only be called explicitly /// from SolverInstance bool evalOutput( const std::string& s_ExtraInfo = "" ); /// This means the solver exits bool evalStatus(SolverInstance::Status status); void printStatistics(std::ostream& ); Env* getEnv() const { return pEnv; } Model* getModel() const { assert(getEnv()->output()); return getEnv()->output(); } /// Get the primary output stream /// First call restores stdout std::ostream& getOutput(); /// Get the secondary output stream std::ostream& getLog(); private: Timer starttime; std::unique_ptr pOut; // file output std::unique_ptr pOfs_non_canon; std::unique_ptr pOfs_raw; int nSolns = 0; std::set sSolsCanon; std::string line_part; // non-finished line from last chunk /// Initialise from ozn file void initFromOzn(const std::string& filename); protected: std::ostream& os; std::ostream& log; std::vector includePaths; std::string stdlibDir; // Basically open output void init(); std::map mapInputStatus; void createInputMap(); void restoreDefaults(); /// Parsing fznsolver's complete raw text output void parseAssignments( std::string& ); /// Checking solution against checker model void checkSolution( std::ostream& os ); bool __evalOutput( std::ostream& os ); bool __evalOutputFinal( bool flag_flush ); bool __evalStatusMsg(SolverInstance::Status status); }; // Passthrough Solns2Out class class Solns2Log { private: std::ostream& _log; std::ostream& _err_log; public: Solns2Log(std::ostream& log, std::ostream& errLog) : _log(log), _err_log(errLog) {} bool feedRawDataChunk(const char* data) { _log << data << std::flush; return true; } std::ostream& getLog(void) { return _err_log; } }; } #endif // __MINIZINC_SOLNS2OUT_H__ libminizinc-2.4.2/include/minizinc/solver.hh000066400000000000000000000142141360574160400211340ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_SOLVER_HH__ #define __MINIZINC_SOLVER_HH__ #include #include #include #include #include #include #include #include namespace MiniZinc { class SolverInitialiser { public: SolverInitialiser(void); }; class SolverFactory; /// SolverRegistry is a storage for all SolverFactories in linked modules class SolverRegistry { public: void addSolverFactory(SolverFactory * ); void removeSolverFactory(SolverFactory * ); typedef std::vector SFStorage; const SFStorage& getSolverFactories() const { return sfstorage; } private: SFStorage sfstorage; }; // SolverRegistry /// this function returns the global SolverRegistry object SolverRegistry* getGlobalSolverRegistry(); /// Representation of flags that can be passed to solvers class MZNFZNSolverFlag { public: /// The type of the solver flag enum FlagType { FT_ARG, FT_NOARG } t; /// The name of the solver flag std::string n; protected: MZNFZNSolverFlag(const FlagType& t0, const std::string& n0) : t(t0), n(n0) {} public: /// Create flag that has an argument static MZNFZNSolverFlag arg(const std::string& n) { return MZNFZNSolverFlag(FT_ARG,n); } /// Create flag that has no argument static MZNFZNSolverFlag noarg(const std::string& n) { return MZNFZNSolverFlag(FT_NOARG,n); } /// Create solver flag from standard flag static MZNFZNSolverFlag std(const std::string& n); /// Create solver flag from extra flag with name \a n and type \a t static MZNFZNSolverFlag extra(const std::string& n, const std::string& t); }; /// SolverFactory's descendants create, store and destroy SolverInstances /// A SolverFactory stores all Instances itself and upon module exit, /// destroys them and de-registers itself from the global SolverRegistry /// An instance of SolverFactory's descendant can be created directly /// or by one of the specialized createF_...() functions class SolverFactory { protected: /// doCreateSI should be implemented to actually allocate a SolverInstance using new() virtual SolverInstanceBase * doCreateSI(Env&, std::ostream&, SolverInstanceBase::Options* opt) = 0; typedef std::vector > SIStorage; SIStorage sistorage; protected: SolverFactory() { getGlobalSolverRegistry()->addSolverFactory(this); } public: virtual ~SolverFactory() { getGlobalSolverRegistry()->removeSolverFactory(this); } public: /// Create solver-specific options object virtual SolverInstanceBase::Options* createOptions(void) = 0; /// Function createSI also adds each SI to the local storage SolverInstanceBase * createSI(Env& env, std::ostream& log, SolverInstanceBase::Options* opt); /// also providing a manual destroy function. /// there is no need to call it upon overall finish - that is taken care of void destroySI(SolverInstanceBase * pSI); public: /// Process an item in the command line. /// Leaving this now like this because this seems simpler. /// We can also pass options internally between modules in this way /// and it only needs 1 format virtual bool processOption(SolverInstanceBase::Options* opt, int& i, std::vector& argv) { return false; } virtual std::string getDescription(SolverInstanceBase::Options* opt=NULL) = 0; virtual std::string getVersion(SolverInstanceBase::Options* opt=NULL) = 0; virtual std::string getId(void) = 0; virtual void printHelp(std::ostream& ) { } }; // SolverFactory // Class MznSolver coordinates flattening and solving. class MznSolver { private: SolverInitialiser _solver_init; enum OptionStatus { OPTION_OK, OPTION_ERROR, OPTION_FINISH }; /// Solver configurations SolverConfigs solver_configs; Flattener flt; SolverInstanceBase* si=0; SolverInstanceBase::Options* si_opt=0; SolverFactory* sf=0; bool is_mzn2fzn=0; std::string executable_name; std::ostream& os; std::ostream& log; public: Solns2Out s2out; /// global options bool flag_verbose=false; bool flag_statistics=false; bool flag_compiler_verbose=false; bool flag_compiler_statistics=false; bool flag_is_solns2out=false; int flag_overall_time_limit=0; public: MznSolver(std::ostream& os = std::cout, std::ostream& log = std::cerr); ~MznSolver(); SolverInstance::Status run(const std::vector& args, const std::string& model = std::string(), const std::string& exeName = std::string("minizinc"), const std::string& modelName = std::string("stdin")); OptionStatus processOptions(std::vector& argv); SolverFactory* getSF() { assert(sf); return sf; } SolverInstanceBase::Options* getSI_OPT() { assert(si_opt); return si_opt; } bool get_flag_verbose() { return flag_verbose; /*getFlt()->get_flag_verbose();*/ } void printUsage(); private: void printHelp(const std::string& selectedSolver=std::string()); /// Flatten model void flatten(const std::string& modelString = std::string(), const std::string& modelName = std::string("stdin")); size_t getNSolvers() { return getGlobalSolverRegistry()->getSolverFactories().size(); } /// If building a flattening exe only. bool ifMzn2Fzn(); bool ifSolns2out(); void addSolverInterface(); void addSolverInterface(SolverFactory* sf); SolverInstance::Status solve(); SolverInstance::Status getFltStatus() { return flt.status; } SolverInstanceBase* getSI() { assert(si); return si; } bool get_flag_statistics() { return flag_statistics; } }; } #endif libminizinc-2.4.2/include/minizinc/solver_config.hh000066400000000000000000000265351360574160400224720ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_SOLVER_CONFIG_HH__ #define __MINIZINC_SOLVER_CONFIG_HH__ #include #include #include #include namespace MiniZinc { /** * \brief Configuration data for individual MiniZinc solvers */ class SolverConfig { public: /// Extra command line flags supported by solver struct ExtraFlag { std::string flag; std::string description; std::string flag_type; std::string default_value; ExtraFlag(const std::string& f, const std::string& d, const std::string& t="bool", const std::string& v="false") : flag(f), description(d), flag_type(t), default_value(v) {} }; protected: /// The configuration file for this solver (or empty string for built-in solvers) std::string _configFile; /// The unique identifier for the solver std::string _id; /// Name of the solver (used for output) std::string _name; /// The path to the executable std::string _executable; /// The path to the executable, after resolving std::string _executable_resolved; /// The path to the solver's MiniZinc library std::string _mznlib; /// The path to the solver's MiniZinc library, after resolving std::string _mznlib_resolved; /// Version string std::string _version; /// MiniZinc library version int _mznlibVersion=1; /// Short description std::string _description; /// Contact email std::string _contact; /// URL for more information std::string _website; /// Whether solver supports MiniZinc input bool _supportsMzn=false; /// Whether solver supports FlatZinc input bool _supportsFzn=true; /// Whether solver supports NL input bool _supportsNL=false; /// Whether solver requires solutions2out processing bool _needsSolns2Out=true; /// Whether solver is a GUI application bool _isGUIApplication=false; /// Whether solver needs path to minizinc executable (passed as --minizinc-exe) bool _needsMznExecutable=false; /// Whether solver needs path to MiniZinc standard library (passed as --stdlib-dir) bool _needsStdlibDir=false; /// Whether solver needs path to symbol table (paths file) (passed as --paths) bool _needsPathsFile=false; /// Supported standard command line flags std::vector _stdFlags; /// Supported extra command line flags (flag and description) std::vector _extraFlags; /// Required command line flags std::vector _requiredFlags; /// Default command line flags (imported from global or user configuration) std::vector _defaultFlags; /// Tags std::vector _tags; public: /// Load solver configuration from \a filename static SolverConfig load(std::string filename); /// Default constructor SolverConfig() {} /// Constructor SolverConfig(const std::string& id, const std::string& version) : _id(id), _version(version) {} /// Return identifier std::string id(void) const { return _id; } /// Return version string std::string version(void) const { return _version; } /// Return configuration file name std::string configFile(void) const { return _configFile; } /// Set configuration file name void configFile(const std::string& s) { _configFile = s; } /// Return name std::string name(void) const { return _name; } // Set name void name(const std::string& s) { _name = s; } /// Return executable path std::string executable(void) const { return _executable; } /// Set executable path void executable(const std::string& s) { _executable = s; } /// Return resolved executable path std::string executable_resolved(void) const { return _executable_resolved; } /// Return MiniZinc library path std::string mznlib(void) const { return _mznlib; } /// Set MiniZinc library path void mznlib(const std::string& s) { _mznlib = s; } /// Return resolved MiniZinc library path std::string mznlib_resolved(void) const { return _mznlib_resolved; } /// Return required MiniZinc library version int mznlibVersion(void) const { return _mznlibVersion; } /// Set required MiniZinc library version void mznlibVersion(int i) { _mznlibVersion = i; } /// Whether solver supports MiniZinc input bool supportsMzn(void) const { return _supportsMzn; } /// Set whether solver supports MiniZinc input void supportsMzn(bool b) { _supportsMzn = b; } /// Whether solver supports FlatZinc input bool supportsFzn(void) const { return _supportsFzn; } /// Set whether solver supports FlatZinc input void supportsFzn(bool b) { _supportsFzn = b; } /// Whether solver supports NL input bool supportsNL(void) const { return _supportsNL; } /// Set whether solver supports NL input void supportsNL(bool b) { _supportsNL = b; } /// Whether solver requires solutions2out processing bool needsSolns2Out(void) const { return _needsSolns2Out; } /// Set whether solver requires solutions2out processing void needsSolns2Out(bool b) { _needsSolns2Out = b; } /// Whether solver is a GUI application bool isGUIApplication(void) const { return _isGUIApplication; } /// Set whether solver is a GUI application void isGUIApplication(bool b) { _isGUIApplication = b; } /// Whether solver needs path to minizinc executable (passed as --minizinc-exe) bool needsMznExecutable(void) const { return _needsMznExecutable; } /// Set whether solver needs path to minizinc executable void needsMznExecutable(bool b) { _needsMznExecutable = b; } /// Whether solver needs path to MiniZinc standard library (passed as --stdlib-dir) bool needsStdlibDir(void) const { return _needsStdlibDir; } /// Set whether solver needs path to MiniZinc standard library void needsStdlibDir(bool b) { _needsStdlibDir = b; } /// Whether solver needs path to symbol table (paths file) (passed as --paths) bool needsPathsFile(void) const { return _needsPathsFile; } /// Set whether solver needs path to symbol table (paths file) void needsPathsFile(bool b) { _needsPathsFile = b; } /// Return short description std::string description(void) const { return _description; } /// Set short description void description(const std::string& s) { _description = s; } /// Return contact email std::string contact(void) const { return _contact; } /// Set contact email void contact(const std::string& s) { _contact = s; } /// Return web site URL std::string website(void) const { return _website; } /// Set web site URL void website(const std::string& s) { _website = s; } /// Return supported standard command line flags const std::vector& stdFlags(void) const { return _stdFlags; } /// Set supported standard command line flags void stdFlags(const std::vector& f) { _stdFlags = f; } /// Return supported extra command line flags const std::vector& extraFlags(void) const { return _extraFlags; } /// Set supported extra command line flags void extraFlags(const std::vector& f) { _extraFlags = f; } /// Return supported required command line flags const std::vector& requiredFlags(void) const { return _requiredFlags; } /// Set supported required command line flags void requiredFlags(const std::vector& f) { _requiredFlags = f; } /// Return default command line flags const std::vector& defaultFlags(void) const { return _defaultFlags; } /// Set default command line flags void defaultFlags(const std::vector& f) { _defaultFlags = f; } /// Return tags const std::vector& tags(void) const { return _tags; } /// Set tags void tags(const std::vector& t) { _tags = t; } /// Test equality bool operator==(const SolverConfig& sc) const { return _id==sc.id() && _version==sc.version(); } }; /// A container for solver configurations class SolverConfigs { protected: /// The solvers std::vector _solvers; typedef std::unordered_map > TagMap; /// Mapping tags to vectors of solvers (indexed into _solvers) TagMap _tags; /// The default solver std::string _defaultSolver; /// The MiniZinc library directory std::string _mznlibDir; /// The solver configurations path std::vector _solver_path; typedef std::unordered_map DefaultMap; /// Mapping from tag to default solver for that tag DefaultMap _tagDefault; typedef std::unordered_map > SolverDefaultMap; /// Mapping from solver id to default options for that solver SolverDefaultMap _solverDefaultOptions; /// Add new solver configuration \a sc void addConfig(const SolverConfig& sc); public: /** \brief Constructor loading configurations from \a solverpath * * Configuration files must be called config.msc and the path * uses platform specific separators (: on Unix-like systems, ; on Windows). */ SolverConfigs(std::ostream& log); /// Return configuration for solver \a s /// The string can be a comma separated list of tags, in which case a /// solver that matches all tags will be returned. The tag can also be /// a solver id. A concrete version can be requested using @. /// Examples: /// config("gecode@6.1.0") would request a gecode solver of version 6.1.0 /// config("mip,internal") would request a MIP solver that uses the internal API /// config("org.minizinc.mip.coin-bc@2.9/1.16 would request a specific version of OSICBC const SolverConfig& config(const std::string& s); /// Return list of all solver ids std::vector solvers(void) const; /// Return search path for solver configs std::vector solverConfigsPath(void) const; /// Return JSON list of all solver configurations std::string solverConfigsJSON(void) const; /// Add a built-in solver static void registerBuiltinSolver(const SolverConfig& sc); /// Default solver const std::string& defaultSolver(void) const { return _defaultSolver; } /// Default solver for tag \a t const std::string& defaultSolver(const std::string& t) { static std::string noDefault; auto it = _tagDefault.find(t); return it==_tagDefault.end() ? noDefault : it->second; } /// MiniZinc library directory const std::string& mznlibDir(void) const { return _mznlibDir; } }; /// An exception thrown when encountering an error in a solver configuration class ConfigException : public Exception { public: /// Construct with message \a msg ConfigException(const std::string& msg) : Exception(msg) {} /// Destructor ~ConfigException(void) throw() {} /// Return description virtual const char* what(void) const throw() { return "MiniZinc: configuration error"; } }; } #endif libminizinc-2.4.2/include/minizinc/solver_instance.hh000066400000000000000000000016431360574160400230220ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_SOLVER_INSTANCE_HH__ #define __MINIZINC_SOLVER_INSTANCE_HH__ namespace MiniZinc { class SolverInstanceBase; #ifdef ERROR // MICROsoft. #undef ERROR #endif class SolverInstance { protected: SolverInstanceBase* _si; public: enum Status { OPT, // For SAT problems this means "search complete" SAT, UNSAT, UNBND, UNSATorUNBND, UNKNOWN, ERROR, NONE }; enum StatusReason { SR_OK=-5, SR_TIME, SR_MEMORY, SR_LIMIT, SR_ERROR }; }; const SolverInstance::Status SolverInstance__ERROR = SolverInstance::ERROR; // just in case... } #endif libminizinc-2.4.2/include/minizinc/solver_instance_base.hh000066400000000000000000000124411360574160400240120ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_SOLVER_INSTANCE_BASE_HH__ #define __MINIZINC_SOLVER_INSTANCE_BASE_HH__ #include #include #include #include #include #include #include namespace MiniZinc { /// An abstract SI class SolverInstanceBase { protected: Env& _env; Solns2Out* pS2Out=0; std::ostream& _log; public: /// Options base class /// A sub-class will be provided by each concrete SolverInstance class Options { public: bool verbose = false; bool printStatistics = false; }; std::unique_ptr _options; typedef SolverInstance::Status Status; typedef SolverInstance::StatusReason StatusReason; Status _status; StatusReason _status_reason; SolverInstanceBase(Env& env, std::ostream& log, Options* options) : _env(env), _log(log), _options(options), _status(SolverInstance::UNKNOWN), _status_reason(SolverInstance::SR_OK) {} virtual ~SolverInstanceBase() { } /// Set/get the environment: virtual Env* getEnv() const { assert(&_env); return &_env; } virtual Env& env(void) const { return *getEnv(); } Solns2Out* getSolns2Out() const { assert(pS2Out); return pS2Out; } void setSolns2Out(Solns2Out* s2o) { pS2Out = s2o; } virtual void printSolution(); // virtual void printSolution(ostream& ); // deprecated /// print statistics in form of comments virtual void printStatistics(bool fLegend=0) { } virtual void printStatisticsLine(bool fLegend=0) { } /// find the next solution virtual Status next(void) = 0; /// generate the solver-instance-representation from the flatzinc model virtual void processFlatZinc(void) = 0; /// clean up input model & flatzinc void cleanupForNonincrementalSolving() { getEnv()->envi().cleanupExceptOutput(); } /// solve the problem instance (according to the solve specification in the flatzinc model) virtual Status solve(void); /// return reason for status given by solve virtual StatusReason reason(void) {return _status_reason;} virtual Status status(void) {return _status;} /// reset the model to its core (removing temporary cts) and the solver to the root node of the search void reset(void); /// reset the solver to the root node of the search TODO: difference between reset() and resetSolver()? virtual void resetSolver(void) = 0; /// reset the solver and add temporary constraints given by the iterator virtual void resetWithConstraints(Model::iterator begin, Model::iterator end); /// add permanent constraints given by the iterator to the solver instance virtual void processPermanentConstraints(Model::iterator begin, Model::iterator end); protected: /// flatten the search annotations, pushing them into the vector \a out void flattenSearchAnnotations(const Annotation& ann, std::vector& out); private: SolverInstanceBase(const SolverInstanceBase&); SolverInstanceBase& operator= (const SolverInstanceBase&); }; /// This implements a solver which is linked and returns its solution by assignSolutionToOutput() class SolverInstanceBase2 : public SolverInstanceBase { protected: virtual Expression* getSolutionValue(Id* id) = 0; public: /// Assign output for all vars: need public for callbacks // Default impl requires a Solns2Out object set up virtual void assignSolutionToOutput(); /// Print solution to setup dest virtual void printSolution(); protected: std::vector _varsWithOutput; // this is to extract fzn vars. Identical to output()? TODO public: SolverInstanceBase2(Env& env, std::ostream& log, SolverInstanceBase::Options* opt) : SolverInstanceBase(env, log, opt) {} }; typedef void (*poster) (SolverInstanceBase&, const Call* call); class Registry { protected: std::unordered_map _registry; SolverInstanceBase& _base; public: Registry(SolverInstanceBase& base) : _base(base) {} void add(const std::string& name, poster p); void post(Call* c); void cleanup() { _registry.clear(); } }; /// Finally, this class also stores a mapping VarDecl->SolverVar and a constraint transformer /// It is a template holding parameterized VarId and Statistics, so cannot have members defined in a .cpp template class SolverInstanceImpl : public SolverInstanceBase2 { public: typename Solver::Statistics _statistics; virtual Statistics& getStatistics() { return _statistics; } typedef typename Solver::Variable VarId; protected: IdMap _variableMap; // this to find solver's variables given an Id Registry _constraintRegistry; public: SolverInstanceImpl(Env& env, std::ostream& log, SolverInstanceBase::Options* opt) : SolverInstanceBase2(env, log, opt), _constraintRegistry(*this) {} }; } #endif libminizinc-2.4.2/include/minizinc/solvers/000077500000000000000000000000001360574160400207745ustar00rootroot00000000000000libminizinc-2.4.2/include/minizinc/solvers/MIP/000077500000000000000000000000001360574160400214215ustar00rootroot00000000000000libminizinc-2.4.2/include/minizinc/solvers/MIP/MIP_cplex_solverfactory.hh000066400000000000000000000010711360574160400265430ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_MIP_CPLEX_SOLVERFACTORY_HH__ #define __MINIZINC_MIP_CPLEX_SOLVERFACTORY_HH__ namespace MiniZinc { class Cplex_SolverFactoryInitialiser { public: Cplex_SolverFactoryInitialiser(void); }; } #endif libminizinc-2.4.2/include/minizinc/solvers/MIP/MIP_cplex_wrap.hh000066400000000000000000000242561360574160400246240ustar00rootroot00000000000000 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MIP_CPLEX_WRAPPER_H__ #define __MIP_CPLEX_WRAPPER_H__ #include #include #include #include // add -DCPLEX_STUDIO_DIR=/opt/ibm/ILOG/CPLEX_Studio1261 to the 1st call of cmake class MIP_cplex_wrapper : public MIP_wrapper { CPXENVptr env = 0; CPXLPptr lp = 0; int status; char cplex_buffer[CPXMESSAGEBUFSIZE]; char cplex_status_buffer[CPXMESSAGEBUFSIZE]; std::vector x; #ifdef CPLEX_PLUGIN void* _cplex_dll; #endif public: class Options : public MiniZinc::SolverInstanceBase::Options { public: int nMIPFocus=0; int nThreads=1; std::string sExportModel; int nTimeout=-1; long int nSolLimit = -1; int nSeed = -1; double nWorkMemLimit=0.5; // although CPLEX 12.10 has default 2GB std::string sNodefileDir; std::string sReadParams; std::string sWriteParams; bool flag_all_solutions = false; double absGap=-1; double relGap=1e-8; double intTol=1e-8; double objDiff=1.0; std::string sCPLEXDLL; bool processOption(int& i, std::vector& argv); static void printHelp(std::ostream& ); }; private: Options* options=nullptr; public: MIP_cplex_wrapper(Options* opt) : options(opt) { openCPLEX(); } virtual ~MIP_cplex_wrapper() { closeCPLEX(); } static std::string getDescription(MiniZinc::SolverInstanceBase::Options* opt=NULL); static std::string getVersion(MiniZinc::SolverInstanceBase::Options* opt=NULL); static std::string getId(void); static std::string getName(void); static std::vector getTags(void); static std::vector getStdFlags(void); static std::string needDllFlag(void); // Statistics& getStatistics() { return _statistics; } // IloConstraintArray *userCuts, *lazyConstraints; /// derived should overload and call the ancestor // virtual void cleanup(); void checkDLL(); void openCPLEX(); void closeCPLEX(); /// actual adding new variables to the solver virtual void doAddVars(size_t n, double *obj, double *lb, double *ub, VarType *vt, std::string *names); /// adding a linear constraint virtual void addRow(int nnz, int *rmatind, double* rmatval, LinConType sense, double rhs, int mask = MaskConsType_Normal, std::string rowName = ""); virtual void setVarBounds( int iVar, double lb, double ub ); virtual void setVarLB( int iVar, double lb ); virtual void setVarUB( int iVar, double ub ); /// Indicator constraint: x[iBVar]==bVal -> lin constr virtual void addIndicatorConstraint(int iBVar, int bVal, int nnz, int *rmatind, double* rmatval, LinConType sense, double rhs, std::string rowName = ""); virtual bool addWarmStart( const std::vector& vars, const std::vector vals ); /// adding an implication // virtual void addImpl() = 0; virtual void setObjSense(int s); // +/-1 for max/min virtual double getInfBound() { return CPX_INFBOUND; } virtual int getNCols() { return dll_CPXgetnumcols (env, lp); } virtual int getNRows() { return dll_CPXgetnumrows (env, lp); } // void setObjUB(double ub) { objUB = ub; } // void addQPUniform(double c) { qpu = c; } // also sets problem type to MIQP unless c=0 virtual void solve(); /// OUTPUT: virtual const double* getValues() { return output.x; } virtual double getObjValue() { return output.objVal; } virtual double getBestBound() { return output.bestBound; } virtual double getCPUTime() { return output.dCPUTime; } virtual Status getStatus() { return output.status; } virtual std::string getStatusName() { return output.statusName; } virtual int getNNodes() { return output.nNodes; } virtual int getNOpen() { return output.nOpenNodes; } // virtual int getNNodes() = 0; // virtual double getTime() = 0; // CPLEX API int (*dll_CPXaddfuncdest) (CPXCENVptr, CPXCHANNELptr, void *, void(*msgfunction)(void *, const char *)); int (*dll_CPXaddindconstr) (CPXCENVptr, CPXLPptr, int, int, int, double, int, int const *, double const *, char const *); int (*dll_CPXaddlazyconstraints) (CPXCENVptr env, CPXLPptr lp, int rcnt, int nzcnt, double const *rhs, char const *sense, int const *rmatbeg, int const *rmatind, double const *rmatval, char **rowname); int (*dll_CPXaddmipstarts) (CPXCENVptr env, CPXLPptr lp, int mcnt, int nzcnt, int const *beg, int const *varindices, double const *values, int const *effortlevel, char **mipstartname); int (*dll_CPXaddrows) (CPXCENVptr env, CPXLPptr lp, int ccnt, int rcnt, int nzcnt, double const *rhs, char const *sense, int const *rmatbeg, int const *rmatind, double const *rmatval, char **colname, char **rowname); int (*dll_CPXaddusercuts) (CPXCENVptr env, CPXLPptr lp, int rcnt, int nzcnt, double const *rhs, char const *sense, int const *rmatbeg, int const *rmatind, double const *rmatval, char **rowname); int (*dll_CPXchgbds) (CPXCENVptr env, CPXLPptr lp, int cnt, int const *indices, char const *lu, double const *bd); int (*dll_CPXchgmipstarts) (CPXCENVptr env, CPXLPptr lp, int mcnt, int const *mipstartindices, int nzcnt, int const *beg, int const *varindices, double const *values, int const *effortlevel); int (*dll_CPXchgobjsen) (CPXCENVptr env, CPXLPptr lp, int maxormin); int (*dll_CPXcloseCPLEX) (CPXENVptr *env_p); CPXLPptr (*dll_CPXcreateprob) (CPXCENVptr env, int *status_p, char const *probname_str); int (*dll_CPXcutcallbackadd) (CPXCENVptr env, void *cbdata, int wherefrom, int nzcnt, double rhs, int sense, int const *cutind, double const *cutval, int purgeable); int (*dll_CPXfreeprob) (CPXCENVptr env, CPXLPptr *lp_p); int (*dll_CPXgetbestobjval) (CPXCENVptr env, CPXCLPptr lp, double *objval_p); int (*dll_CPXgetcallbackincumbent) (CPXCENVptr env, void *cbdata, int wherefrom, double *x, int begin, int end); int (*dll_CPXgetcallbackinfo) (CPXCENVptr env, void *cbdata, int wherefrom, int whichinfo, void *result_p); int (*dll_CPXgetcallbacknodeinfo) (CPXCENVptr env, void *cbdata, int wherefrom, int nodeindex, int whichinfo, void *result_p); int (*dll_CPXgetcallbacknodex) (CPXCENVptr env, void *cbdata, int wherefrom, double *x, int begin, int end); int (*dll_CPXgetchannels) (CPXCENVptr env, CPXCHANNELptr *cpxresults_p, CPXCHANNELptr *cpxwarning_p, CPXCHANNELptr *cpxerror_p, CPXCHANNELptr *cpxlog_p); int (*dll_CPXgetdettime) (CPXCENVptr env, double *dettimestamp_p); CPXCCHARptr (*dll_CPXgeterrorstring) (CPXCENVptr env, int errcode, char *buffer_str); int (*dll_CPXgetmipstartindex) (CPXCENVptr env, CPXCLPptr lp, char const *lname_str, int *index_p); int (*dll_CPXgetnodecnt) (CPXCENVptr env, CPXCLPptr lp); int (*dll_CPXgetnodeleftcnt) (CPXCENVptr env, CPXCLPptr lp); int (*dll_CPXgetnumcols) (CPXCENVptr env, CPXCLPptr lp); int (*dll_CPXgetnumrows) (CPXCENVptr env, CPXCLPptr lp); int (*dll_CPXgetobjsen) (CPXCENVptr env, CPXCLPptr lp); int (*dll_CPXgetobjval) (CPXCENVptr env, CPXCLPptr lp, double *objval_p); int (*dll_CPXgetsolnpoolnumsolns) (CPXCENVptr env, CPXCLPptr lp); int (*dll_CPXgetstat) (CPXCENVptr env, CPXCLPptr lp); CPXCHARptr (*dll_CPXgetstatstring) (CPXCENVptr env, int statind, char *buffer_str); int (*dll_CPXgettime) (CPXCENVptr env, double *timestamp_p); int (*dll_CPXgetx) (CPXCENVptr env, CPXCLPptr lp, double *x, int begin, int end); int (*dll_CPXmipopt) (CPXCENVptr env, CPXLPptr lp); int (*dll_CPXnewcols) (CPXCENVptr env, CPXLPptr lp, int ccnt, double const *obj, double const *lb, double const *ub, char const *xctype, char **colname); CPXENVptr (*dll_CPXopenCPLEX) (int *status_p); int (*dll_CPXreadcopyparam) (CPXENVptr env, char const *filename_str); int (*dll_CPXsetdblparam) (CPXENVptr env, int whichparam, double newvalue); int (*dll_CPXsetinfocallbackfunc) (CPXENVptr env, int(*callback)(CPXCENVptr, void *, int, void *), void *cbhandle); int (*dll_CPXsetintparam) (CPXENVptr env, int whichparam, CPXINT newvalue); int (*dll_CPXsetstrparam) (CPXENVptr env, int whichparam, char const * newvalue); int (*dll_CPXsetlazyconstraintcallbackfunc) (CPXENVptr env, int(*lazyconcallback)(CALLBACK_CUT_ARGS), void *cbhandle); int (*dll_CPXsetusercutcallbackfunc) (CPXENVptr env, int(*cutcallback)(CALLBACK_CUT_ARGS), void *cbhandle); CPXCCHARptr (*dll_CPXversion) (CPXCENVptr env); int (*dll_CPXwriteparam) (CPXCENVptr env, char const *filename_str); int (*dll_CPXwriteprob) (CPXCENVptr env, CPXCLPptr lp, char const *filename_str, char const *filetype_str); protected: void wrap_assert(bool , std::string , bool fTerm=true); /// Need to consider the 100 status codes in CPLEX and change with every version? TODO Status convertStatus(int cplexStatus); }; #endif // __MIP_CPLEX_WRAPPER_H__ libminizinc-2.4.2/include/minizinc/solvers/MIP/MIP_gurobi_solverfactory.hh000066400000000000000000000010751360574160400267230ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_MIP_GUROBI_SOLVERFACTORY_HH__ #define __MINIZINC_MIP_GUROBI_SOLVERFACTORY_HH__ namespace MiniZinc { class Gurobi_SolverFactoryInitialiser { public: Gurobi_SolverFactoryInitialiser(void); }; } #endif libminizinc-2.4.2/include/minizinc/solvers/MIP/MIP_gurobi_wrap.hh000066400000000000000000000211561360574160400247740ustar00rootroot00000000000000 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MIP_GUROBI_WRAPPER_H__ #define __MIP_GUROBI_WRAPPER_H__ #include #include extern "C" { #include // need GUROBI_HOME defined } class MIP_gurobi_wrapper : public MIP_wrapper { GRBenv * env = 0; GRBmodel * model = 0; #ifdef GUROBI_PLUGIN void * gurobi_dll; #endif int error; std::string gurobi_buffer; // [GRB_MESSAGEBUFSIZE]; std::string gurobi_status_buffer; // [GRB_MESSAGEBUFSIZE]; std::vector x; public: class Options : public MiniZinc::SolverInstanceBase::Options { public: int nMIPFocus=0; int nFreeSearch=1; int nThreads=1; std::string sExportModel; int nTimeout1000=-1; int nTimeoutFeas1000=-1; long int nSolLimit = -1; int nSeed = -1; double nWorkMemLimit=0.5; std::string sNodefileDir; std::string sReadParams; std::string sWriteParams; bool flag_all_solutions = false; double absGap=-1; double relGap=1e-8; double feasTol=1e-8; double intTol=1e-8; double objDiff=1.0; std::string sGurobiDLL; bool processOption(int& i, std::vector& argv); static void printHelp(std::ostream& ); }; private: Options* options=nullptr; public: void (__stdcall *dll_GRBversion) (int*, int*, int*); int (__stdcall *dll_GRBaddconstr) (GRBmodel *model, int numnz, int *cind, double *cval, char sense, double rhs, const char *constrname); int (__stdcall *dll_GRBaddgenconstrIndicator) ( GRBmodel *model, const char *name, int binvar, int binval, int nvars, const int* ind, const double* val, char sense, double rhs ); int (__stdcall *dll_GRBaddvars) (GRBmodel *model, int numvars, int numnz, int *vbeg, int *vind, double *vval, double *obj, double *lb, double *ub, char *vtype, char **varnames); int (__stdcall *dll_GRBcbcut) (void *cbdata, int cutlen, const int *cutind, const double *cutval, char cutsense, double cutrhs); int (__stdcall *dll_GRBcbget) (void *cbdata, int where, int what, void *resultP); int (__stdcall *dll_GRBcblazy) (void *cbdata, int lazylen, const int *lazyind, const double *lazyval, char lazysense, double lazyrhs); void (__stdcall *dll_GRBfreeenv) (GRBenv *env); int (__stdcall *dll_GRBfreemodel) (GRBmodel *model); int (__stdcall *dll_GRBgetdblattr) (GRBmodel *model, const char *attrname, double *valueP); int (__stdcall *dll_GRBgetdblattrarray) (GRBmodel *model, const char *attrname, int first, int len, double *values); GRBenv * (__stdcall *dll_GRBgetenv) (GRBmodel *model); const char * (__stdcall *dll_GRBgeterrormsg) (GRBenv *env); int (__stdcall *dll_GRBgetintattr) (GRBmodel *model, const char *attrname, int *valueP); int (__stdcall *dll_GRBloadenv) (GRBenv **envP, const char *logfilename); int (__stdcall *dll_GRBnewmodel) (GRBenv *env, GRBmodel **modelP, const char *Pname, int numvars, double *obj, double *lb, double *ub, char *vtype, char **varnames); int (__stdcall *dll_GRBoptimize) (GRBmodel *model); int (__stdcall *dll_GRBreadparams) (GRBenv *env, const char *filename); int (__stdcall *dll_GRBsetcallbackfunc) (GRBmodel *model, int (__stdcall *cb)(CB_ARGS), void *usrdata); int (__stdcall *dll_GRBsetdblparam) (GRBenv *env, const char *paramname, double value); int (__stdcall *dll_GRBsetintparam) (GRBenv *env, const char *paramname, int value); int (__stdcall *dll_GRBsetintattr) (GRBmodel *model, const char *attrname, int newvalue); int (__stdcall *dll_GRBsetdblattrelement) (GRBmodel *model, const char *attrname, int iv, double v); int (__stdcall *dll_GRBsetintattrlist) (GRBmodel *model, const char *attrname, int len, int *ind, int *newvalues); int (__stdcall *dll_GRBsetdblattrlist) (GRBmodel *model, const char *attrname, int len, int *ind, double *newvalues); int (__stdcall *dll_GRBsetstrparam) (GRBenv *env, const char *paramname, const char *value); void (__stdcall *dll_GRBterminate) (GRBmodel* model); int (__stdcall *dll_GRBupdatemodel) (GRBmodel *model); int (__stdcall *dll_GRBwrite) (GRBmodel *model, const char *filename); int (__stdcall *dll_GRBwriteparams) (GRBenv *env, const char *filename); int (__stdcall *dll_GRBgetintparam) (GRBenv *env, const char *paramname, int *valueP); public: MIP_gurobi_wrapper(Options* opt) : options(opt) { if (opt) openGUROBI(); } virtual ~MIP_gurobi_wrapper() { closeGUROBI(); } static std::string getDescription(MiniZinc::SolverInstanceBase::Options* opt=NULL); static std::string getVersion(MiniZinc::SolverInstanceBase::Options* opt=NULL); static std::string getId(void); static std::string getName(void); static std::vector getTags(void); static std::vector getStdFlags(void); static std::string needDllFlag(void); // Statistics& getStatistics() { return _statistics; } // IloConstraintArray *userCuts, *lazyConstraints; /// derived should overload and call the ancestor // virtual void cleanup(); void checkDLL(); void openGUROBI(); void closeGUROBI(); /// actual adding new variables to the solver virtual void doAddVars(size_t n, double *obj, double *lb, double *ub, VarType *vt, std::string *names); /// adding a linear constraint virtual void addRow(int nnz, int *rmatind, double* rmatval, LinConType sense, double rhs, int mask = MaskConsType_Normal, std::string rowName = ""); virtual void setVarBounds( int iVar, double lb, double ub ); virtual void setVarLB( int iVar, double lb ); virtual void setVarUB( int iVar, double ub ); /// Indicator constraint: x[iBVar]==bVal -> lin constr virtual void addIndicatorConstraint(int iBVar, int bVal, int nnz, int *rmatind, double* rmatval, LinConType sense, double rhs, std::string rowName = ""); virtual int getFreeSearch(); virtual bool addSearch( const std::vector& vars, const std::vector pri ); virtual bool addWarmStart( const std::vector& vars, const std::vector vals ); int nRows=0; // to count rows in order tp notice lazy constraints std::vector nLazyIdx; std::vector nLazyValue; /// adding an implication // virtual void addImpl() = 0; virtual void setObjSense(int s); // +/-1 for max/min virtual double getInfBound() { return GRB_INFINITY; } virtual int getNCols() { dll_GRBupdatemodel(model); int cols; error = dll_GRBgetintattr(model, GRB_INT_ATTR_NUMVARS, &cols); return cols; } virtual int getNRows() { dll_GRBupdatemodel(model); int cols; error = dll_GRBgetintattr(model, GRB_INT_ATTR_NUMCONSTRS, &cols); return cols; } // void setObjUB(double ub) { objUB = ub; } // void addQPUniform(double c) { qpu = c; } // also sets problem type to MIQP unless c=0 virtual void solve(); /// OUTPUT: virtual const double* getValues() { return output.x; } virtual double getObjValue() { return output.objVal; } virtual double getBestBound() { return output.bestBound; } virtual double getCPUTime() { return output.dCPUTime; } virtual Status getStatus() { return output.status; } virtual std::string getStatusName() { return output.statusName; } virtual int getNNodes() { return output.nNodes; } virtual int getNOpen() { return output.nOpenNodes; } // virtual int getNNodes() = 0; // virtual double getTime() = 0; protected: void wrap_assert(bool , std::string , bool fTerm=true); /// Need to consider the 100 status codes in GUROBI and change with every version? TODO Status convertStatus(int gurobiStatus); }; #endif // __MIP_GUROBI_WRAPPER_H__ libminizinc-2.4.2/include/minizinc/solvers/MIP/MIP_osicbc_solverfactory.hh000066400000000000000000000010761360574160400266770ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_MIP_OSICBC_SOLVERFACTORY_HH__ #define __MINIZINC_MIP_OSICBC_SOLVERFACTORY_HH__ namespace MiniZinc { class OSICBC_SolverFactoryInitialiser { public: OSICBC_SolverFactoryInitialiser(void); }; } #endif libminizinc-2.4.2/include/minizinc/solvers/MIP/MIP_osicbc_wrap.hh000066400000000000000000000124351360574160400247470ustar00rootroot00000000000000 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MIP_OSICBC_WRAPPER_H__ #define __MIP_OSICBC_WRAPPER_H__ #include #include // CMakeLists.txt needs OSICBC_HOME defined // #include // #include // #include // #include // #include // #include #include #include // #include class MIP_osicbc_wrapper : public MIP_wrapper { // OsiCbcSolverInterface osi; // deprecated in Cbc 2.9.6 OsiClpSolverInterface osi; // CoinPackedMatrix* matrix = 0; int error; std::string osicbc_buffer; // [CBC_MESSAGEBUFSIZE]; // string osicbc_status_buffer; // [CBC_MESSAGEBUFSIZE]; std::vector x; // To add constraints: // vector rowStarts, columns; std::vector rows; std::vector //element, rowlb, rowub; std::unordered_map warmstart; // this accumulates warmstart infos public: class Options : public MiniZinc::SolverInstanceBase::Options { public: int nThreads=1; std::string sExportModel; int nTimeout=0; long int nSolLimit = -1; double nWorkMemLimit=-1; std::string sReadParams; std::string sWriteParams; bool flag_all_solutions = false; double absGap=-1; double relGap=1e-8; double intTol=1e-8; double objDiff=1.0; std::string cbc_cmdOptions; bool processOption(int& i, std::vector& argv); static void printHelp(std::ostream& ); }; private: Options* options=nullptr; public: MIP_osicbc_wrapper(Options* opt) : options(opt) { openOSICBC(); } virtual ~MIP_osicbc_wrapper() { closeOSICBC(); } static std::string getDescription(MiniZinc::SolverInstanceBase::Options* opt=NULL); static std::string getVersion(MiniZinc::SolverInstanceBase::Options* opt=NULL); static std::string getId(void); static std::string getName(void); static std::vector getTags(void); static std::vector getStdFlags(void); static std::string needDllFlag(void) { return ""; } void printVersion(std::ostream& ); void printHelp(std::ostream& ); // Statistics& getStatistics() { return _statistics; } // IloConstraintArray *userCuts, *lazyConstraints; /// derived should overload and call the ancestor // virtual void cleanup(); void openOSICBC() { } void closeOSICBC() { } /// actual adding new variables to the solver virtual void doAddVars(size_t n, double *obj, double *lb, double *ub, VarType *vt, std::string *names); void addPhase1Vars() { if (fVerbose) std::cerr << " MIP_osicbc_wrapper: delaying physical addition of variables..." << std::endl; } /// adding a linear constraint virtual void addRow(int nnz, int *rmatind, double* rmatval, LinConType sense, double rhs, int mask = MaskConsType_Normal, std::string rowName = ""); /// adding an implication // virtual void addImpl() = 0; virtual bool addWarmStart( const std::vector& vars, const std::vector vals ); virtual void setObjSense(int s); // +/-1 for max/min virtual double getInfBound() { return osi.getInfinity(); } virtual int getNCols() { int nc = osi.getNumCols(); return nc ? nc : colLB.size(); } virtual int getNColsModel() { return osi.getNumCols(); } virtual int getNRows() { if (rowlb.size()) return rowlb.size(); return osi.getNumRows(); } // void setObjUB(double ub) { objUB = ub; } // void addQPUniform(double c) { qpu = c; } // also sets problem type to MIQP unless c=0 virtual void solve(); /// OUTPUT: virtual const double* getValues() { return output.x; } virtual double getObjValue() { return output.objVal; } virtual double getBestBound() { return output.bestBound; } virtual double getCPUTime() { return output.dCPUTime; } virtual Status getStatus() { return output.status; } virtual std::string getStatusName() { return output.statusName; } virtual int getNNodes() { return output.nNodes; } virtual int getNOpen() { return output.nOpenNodes; } // virtual int getNNodes() = 0; // virtual double getTime() = 0; protected: // OsiSolverInterface& getOsiSolver(void) { return osi; } void wrap_assert(bool , std::string , bool fTerm=true); /// Need to consider the 100 status codes in OSICBC and change with every version? TODO Status convertStatus(CbcModel *pModel); Status convertStatus(); }; #endif // __MIP_OSICBC_WRAPPER_H__ libminizinc-2.4.2/include/minizinc/solvers/MIP/MIP_scip_solverfactory.hh000066400000000000000000000010661360574160400263720ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_MIP_SCIP_SOLVERFACTORY_HH__ #define __MINIZINC_MIP_SCIP_SOLVERFACTORY_HH__ namespace MiniZinc { class SCIP_SolverFactoryInitialiser { public: SCIP_SolverFactoryInitialiser(void); }; } #endif libminizinc-2.4.2/include/minizinc/solvers/MIP/MIP_scip_wrap.hh000066400000000000000000000133501360574160400244400ustar00rootroot00000000000000 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MIP_SCIP_WRAPPER_H__ #define __MIP_SCIP_WRAPPER_H__ #include #include #include #include class MIP_scip_wrapper : public MIP_wrapper { SCIP *scip = 0; // SCIP_Retcode retcode = SCIP_OKAY; // char scip_buffer[SCIP_MESSAGEBUFSIZE]; // char scip_status_buffer[SCIP_MESSAGEBUFSIZE]; std::vector scipVars; virtual SCIP_RETCODE delSCIPVars(); std::vector x; public: class Options : public MiniZinc::SolverInstanceBase::Options { public: int nThreads=1; std::string sExportModel; int nTimeout=-1; double nWorkMemLimit=-1; std::string sReadParams; std::string sWriteParams; bool flag_all_solutions = false; double absGap=-1; double relGap=1e-8; double intTol=1e-8; double objDiff=1.0; bool processOption(int& i, std::vector& argv); static void printHelp(std::ostream& ); }; private: Options* options=nullptr; public: MIP_scip_wrapper(Options* opt) : options(opt) { wrap_assert( openSCIP() ); } virtual ~MIP_scip_wrapper() { wrap_assert( delSCIPVars() ); wrap_assert( closeSCIP() ); } static std::string getDescription(MiniZinc::SolverInstanceBase::Options* opt=NULL); static std::string getVersion(MiniZinc::SolverInstanceBase::Options* opt=NULL); static std::string getId(void); static std::string getName(void); static std::vector getTags(void); static std::vector getStdFlags(void); static std::string needDllFlag(void); bool processOption(int& i, int argc, const char** argv); void printVersion(std::ostream& ); void printHelp(std::ostream& ); // Statistics& getStatistics() { return _statistics; } // IloConstraintArray *userCuts, *lazyConstraints; /// derived should overload and call the ancestor // virtual void cleanup(); SCIP_RETCODE openSCIP(); SCIP_RETCODE closeSCIP(); /// actual adding new variables to the solver virtual void doAddVars(size_t n, double *obj, double *lb, double *ub, VarType *vt, std::string *names) { wrap_assert(doAddVars_SCIP(n, obj, lb, ub, vt, names)); } virtual SCIP_RETCODE doAddVars_SCIP(size_t n, double *obj, double *lb, double *ub, VarType *vt, std::string *names); virtual void setVarBounds( int iVar, double lb, double ub ); virtual void setVarLB( int iVar, double lb ); virtual void setVarUB( int iVar, double ub ); /// adding a linear constraint virtual void addRow(int nnz, int *rmatind, double* rmatval, LinConType sense, double rhs, int mask = MaskConsType_Normal, std::string rowName = "") { wrap_assert(addRow_SCIP(nnz, rmatind, rmatval, sense, rhs, mask, rowName)); } virtual SCIP_RETCODE addRow_SCIP(int nnz, int *rmatind, double* rmatval, LinConType sense, double rhs, int mask = MaskConsType_Normal, std::string rowName = ""); /// adding an implication // virtual void addImpl() = 0; /// Indicator constraint: x[iBVar]==bVal -> lin constr virtual void addIndicatorConstraint(int iBVar, int bVal, int nnz, int *rmatind, double* rmatval, LinConType sense, double rhs, std::string rowName = ""); /// Bounds disj for SCIP virtual void addBoundsDisj(int n, double *fUB, double *bnd, int* vars, int nF, double *fUBF, double *bndF, int* varsF, std::string rowName = ""); /// Cumulative, currently SCIP only virtual void addCumulative(int nnz, int *rmatind, double* d, double* r, double b, std::string rowName=""); virtual void setObjSense(int s) { // +/-1 for max/min wrap_assert( setObjSense_SCIP(s) ); } virtual SCIP_RETCODE setObjSense_SCIP(int s); virtual double getInfBound() { return SCIPinfinity(scip); } virtual int getNCols() { return SCIPgetNVars (scip); } virtual int getNRows() { return SCIPgetNConss (scip); } // void setObjUB(double ub) { objUB = ub; } // void addQPUniform(double c) { qpu = c; } // also sets problem type to MIQP unless c=0 virtual void solve() { wrap_assert(solve_SCIP()); } virtual SCIP_RETCODE solve_SCIP(); /// OUTPUT: virtual const double* getValues() { return output.x; } virtual double getObjValue() { return output.objVal; } virtual double getBestBound() { return output.bestBound; } virtual double getCPUTime() { return output.dCPUTime; } virtual Status getStatus() { return output.status; } virtual std::string getStatusName() { return output.statusName; } virtual int getNNodes() { return output.nNodes; } virtual int getNOpen() { return output.nOpenNodes; } // virtual int getNNodes() = 0; // virtual double getTime() = 0; protected: void wrap_assert(SCIP_RETCODE , std::string="" , bool fTerm=true); /// Need to consider the 100 status codes in SCIP and change with every version? TODO Status convertStatus(SCIP_STATUS scipStatus); public: /// Default MZN library for SCIP static std::string getMznLib(); }; #endif // __MIP_SCIP_WRAPPER_H__ libminizinc-2.4.2/include/minizinc/solvers/MIP/MIP_solverinstance.hh000066400000000000000000000120571360574160400255130ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_MIP_SOLVER_INSTANCE_H__ #define __MINIZINC_MIP_SOLVER_INSTANCE_H__ #include #include #include namespace MiniZinc { // can be redefined as compilation parameter #ifndef GETMIPWRAPPER #define GETMIPWRAPPER MIP_WrapperFactory::GetDefaultMIPWrapper() #endif class MIP_solver { public: typedef MIP_wrapper::VarId Variable; typedef MiniZinc::Statistics Statistics; }; /// Generic cut generator /// Callback should be able to produce previously generated cuts again if needed [Gurobi] class CutGen { public: virtual ~CutGen() { } /// Say what type of cuts virtual int getMask() = 0; /// Adds new cuts to the 2nd parameter virtual void generate(const MIP_wrapper::Output&, MIP_wrapper::CutInput&) = 0; virtual void print( std::ostream& ) { } }; /// XBZ cut generator class XBZCutGen : public CutGen { XBZCutGen() { } MIP_wrapper* pMIP=0; public: XBZCutGen( MIP_wrapper* pw ) : pMIP(pw) { } std::vector varX, varB; /// Say what type of cuts virtual int getMask() { return MIP_wrapper::MaskConsType_Usercut; } MIP_wrapper::VarId varZ; void generate(const MIP_wrapper::Output&, MIP_wrapper::CutInput&); void print( std::ostream& ); }; /// SEC cut generator for circuit class SECCutGen : public CutGen { SECCutGen() { } MIP_wrapper* pMIP=0; public: SECCutGen( MIP_wrapper* pw ) : pMIP(pw) { } /// Say what type of cuts virtual int getMask() { return MIP_wrapper::MaskConsType_Lazy | MIP_wrapper::MaskConsType_Usercut; } std::vector varXij; int nN=0; // N nodes /// returns error message if fails std::string validate() const; void generate(const MIP_wrapper::Output&, MIP_wrapper::CutInput&); void print( std::ostream& ); }; template class MIP_solverinstance : public SolverInstanceImpl { using SolverInstanceBase::_log; protected: const std::unique_ptr mip_wrap; std::vector< std::unique_ptr > cutGenerators; public: void registerCutGenerator( std::unique_ptr&& pCG ) { getMIPWrapper()->cbui.cutMask |= pCG->getMask(); cutGenerators.push_back( move( pCG ) ); } public: double lastIncumbent; double dObjVarLB=-1e300, dObjVarUB=1e300; public: MIP_solverinstance(Env& env, std::ostream& log, typename MIPWrapper::Options* opt) : SolverInstanceImpl(env,log,opt), mip_wrap(new MIPWrapper(opt)) { assert(mip_wrap.get()); registerConstraints(); } virtual MIP_wrapper* getMIPWrapper() const { return mip_wrap.get(); } virtual Status next(void) { assert(0); return SolverInstance::UNKNOWN; } virtual void processFlatZinc(void); virtual void processWarmstartAnnotations( const Annotation& ann ); virtual void processSearchAnnotations( const Annotation& ann ); virtual Status solve(void); virtual void resetSolver(void) { } virtual void genCuts ( const MIP_wrapper::Output& , MIP_wrapper::CutInput& , bool fMIPSol); // void assignSolutionToOutput(); // needs to be public for the callback? virtual void printStatistics(bool fLegend=0); virtual void printStatisticsLine(bool fLegend=0); public: /// creates a var for a literal, if necessary VarId exprToVar(Expression* e); void exprToArray(Expression* e, std::vector &vals); void exprToVarArray(Expression* e, std::vector &vars); std::pair exprToConstEasy(Expression* e); double exprToConst(Expression* e); Expression* getSolutionValue(Id* id); void registerConstraints(void); }; // MIP_solverinstance template class MIP_SolverFactory: public SolverFactory { public: MIP_SolverFactory(void); SolverInstanceBase::Options* createOptions(void) { return new typename MIPWrapper::Options; } SolverInstanceBase* doCreateSI(Env& env, std::ostream& log, SolverInstanceBase::Options* opt) { return new MIP_solverinstance(env,log,static_cast(opt)); } bool processOption(SolverInstanceBase::Options* opt, int& i, std::vector& argv); std::string getDescription(SolverInstanceBase::Options* opt=NULL); std::string getVersion(SolverInstanceBase::Options* opt=NULL); std::string getId( ); void printHelp(std::ostream& os) { MIPWrapper::Options::printHelp(os); } }; } #include #endif // __MINIZINC_MIP_SOLVER_INSTANCE_H__ libminizinc-2.4.2/include/minizinc/solvers/MIP/MIP_solverinstance.hpp000066400000000000000000001135421360574160400257040ustar00rootroot00000000000000#include namespace MiniZinc { template MIP_SolverFactory::MIP_SolverFactory(void) { std::vector requiredFlags; std::string dllFlag = MIPWrapper::needDllFlag(); if (dllFlag.size()) requiredFlags.push_back(dllFlag); SolverConfig sc(getId(), MIPWrapper::getVersion()); sc.name(MIPWrapper::getName()); sc.mznlib(MIPWrapper::getMznLib()); sc.mznlibVersion(1); sc.supportsMzn(true); sc.description("MiniZinc MIP solver plugin"); sc.requiredFlags(requiredFlags); sc.tags(MIPWrapper::getTags()); sc.stdFlags(MIPWrapper::getStdFlags()); SolverConfigs::registerBuiltinSolver(sc); } template bool MIP_SolverFactory::processOption(SolverInstanceBase::Options* opt, int& i, std::vector& argv) { if (argv[i]=="--verbose-solving") { opt->verbose = true; return true; } else if (argv[i]=="--solver-statistics") { opt->printStatistics = true; return true; } else { return static_cast(*opt).processOption(i, argv); } } template std::string MIP_SolverFactory::getDescription(SolverInstanceBase::Options* opt) { std::string v = "MIP solver plugin, compiled " __DATE__ ", using: " + MIPWrapper::getDescription(opt); return v; } template std::string MIP_SolverFactory::getVersion(SolverInstanceBase::Options* opt) { return MIPWrapper::getVersion(opt); } template std::string MIP_SolverFactory::getId() { return "org.minizinc.mip."+MIPWrapper::getId(); } template MIP_solver::Variable MIP_solverinstance::exprToVar(Expression* arg) { if (Id* ident = arg->dyn_cast()) { return _variableMap.get(ident->decl()->id()); } else return mip_wrap->addLitVar( exprToConst( arg ) ); } template void MIP_solverinstance::exprToVarArray(Expression* arg, std::vector &vars) { ArrayLit* al = eval_array_lit(getEnv()->envi(), arg); vars.clear(); vars.reserve(al->size()); for (unsigned int i=0; isize(); i++) vars.push_back(exprToVar((*al)[i])); } template std::pair MIP_solverinstance::exprToConstEasy(Expression* e) { std::pair res { 0.0, true }; if (IntLit* il = e->dyn_cast()) { res.first = ( static_cast(il->v().toInt()) ); } else if (FloatLit* fl = e->dyn_cast()) { res.first = ( fl->v().toDouble() ); } else if (BoolLit* bl = e->dyn_cast()) { res.first = ( bl->v() ); } else { res.second = false; } return res; } template double MIP_solverinstance::exprToConst(Expression* e) { const auto e2ce = exprToConstEasy( e ); if ( !e2ce.second ) { std::ostringstream oss; oss << "ExprToConst: expected a numeric/bool literal, getting " << *e; throw InternalError( oss.str() ); } return e2ce.first; } template void MIP_solverinstance::exprToArray(Expression* arg, std::vector &vals) { ArrayLit* al = eval_array_lit(getEnv()->envi(), arg); vals.clear(); vals.reserve(al->size()); for (unsigned int i=0; isize(); i++) { vals.push_back( exprToConst( (*al)[i] ) ); } } template void MIP_solverinstance::processSearchAnnotations(const Annotation& ann) { if ( 1==getMIPWrapper()->getFreeSearch() ) return; std::vector aAnns; flattenSearchAnnotations( ann, aAnns ); std::vector vars; std::vector aPri; // priorities int nArrayAnns = 0; for ( auto iA=0; iAisa() ) { Call* pC = pE->cast(); const auto cId = pC->id().str(); if ( "int_search"==cId || "float_search"==cId ) { ArrayLit* alV = nullptr; if ( !pC->n_args() || nullptr == (alV = eval_array_lit(_env.envi(),pC->arg(0))) ) { std::cerr << " SEARCH ANN: '" << (*pC) << "' is unknown. " << std::endl; continue; } ++nArrayAnns; for (unsigned int i=0; isize(); i++) { if (Id* ident = (*alV)[i]->dyn_cast()) { vars.push_back( exprToVar( ident ) ); aPri.push_back( static_cast(aAnns.size())-iA ); // level search by default } // else ignore } } } } if ( vars.size() ) { if ( 2==getMIPWrapper()->getFreeSearch() ) { for ( int i=0; iaddSearch( vars, aPri ) ) std::cerr << "\nWARNING: MIP backend seems to ignore search strategy." << std::endl; else std::cerr << " MIP: added " << vars.size() << " variable branching priorities from " << nArrayAnns << " arrays." << std::endl; } } template void MIP_solverinstance::processWarmstartAnnotations(const Annotation& ann) { int nVal = 0; for(ExpressionSetIter i = ann.begin(); i != ann.end(); ++i) { Expression* e = *i; if ( e->isa() ) { Call* c = e->cast(); if ( c->id().str() == "warm_start_array" || c->id().str() == "seq_search" ) { ArrayLit* anns = c->arg(0)->cast(); for(unsigned int i=0; isize(); i++) { Annotation subann; subann.add((*anns)[i]); processWarmstartAnnotations( subann ); } } else if ( c->id().str() == "warm_start" ) { MZN_ASSERT_HARD_MSG( c->n_args()>=2, "ERROR: warm_start needs 2 array args" ); std::vector coefs; std::vector vars; /// Process coefs & vars together to eliminate literals (problem with Gurobi's updatemodel()'s) ArrayLit* alC = eval_array_lit(_env.envi(), c->arg(1)); MZN_ASSERT_HARD_MSG( 0!=alC, "ERROR: warm_start needs 2 array args" ); coefs.reserve(alC->size()); ArrayLit* alV = eval_array_lit(_env.envi(), c->arg(0)); MZN_ASSERT_HARD_MSG( 0!=alV, "ERROR: warm_start needs 2 array args" ); vars.reserve(alV->size()); for (unsigned int i=0; isize() && isize(); i++) { const auto e2c = exprToConstEasy( (*alC)[i] ); /// Check if it is not an opt int etc. and a proper variable if (e2c.second) if (Id* ident = (*alV)[i]->dyn_cast()) { coefs.push_back( e2c.first ); vars.push_back( exprToVar( ident ) ); } // else ignore } assert(coefs.size() == vars.size()); nVal += static_cast(coefs.size()); if ( coefs.size() && !getMIPWrapper()->addWarmStart( vars, coefs ) ) { std::cerr << "\nWARNING: MIP backend seems to ignore warm starts" << std::endl; return; } } } } if ( nVal && getMIPWrapper()->fVerbose ) { std::cerr << " MIP: added " << nVal << " MIPstart values..." << std::flush; } } template void MIP_solverinstance::processFlatZinc(void) { mip_wrap->fVerbose = _options->verbose; SolveI* solveItem = getEnv()->flat()->solveItem(); VarDecl* objVd = NULL; if (solveItem->st() != SolveI::SolveType::ST_SAT) { if(Id* id = solveItem->e()->dyn_cast()) { objVd = id->decl(); } else { std::cerr << "Objective must be Id: " << solveItem->e() << std::endl; throw InternalError("Objective must be Id"); } } for (VarDeclIterator it = getEnv()->flat()->begin_vardecls(); it != getEnv()->flat()->end_vardecls(); ++it) { if (it->removed()) { continue; } VarDecl* vd = it->e(); if(!vd->ann().isEmpty()) { if(vd->ann().containsCall(constants().ann.output_array.aststr()) || vd->ann().contains(constants().ann.output_var) ) { _varsWithOutput.push_back(vd); // std::cerr << (*vd); // if ( vd->e() ) // cerr << " = " << (*vd->e()); // cerr << endl; } } if (vd->type().dim() == 0 && it->e()->type().isvar() && !it->removed()) { MiniZinc::TypeInst* ti = it->e()->ti(); MIP_wrapper::VarType vType = MIP_wrapper::VarType::REAL; // fInt = false; if (ti->type().isvarint() || ti->type().isint()) vType = MIP_wrapper::VarType::INT; else if (ti->type().isvarbool() || ti->type().isbool()) { vType = MIP_wrapper::VarType::BINARY; } else if (ti->type().isvarfloat() || ti->type().isfloat()) { } else { std::stringstream ssm; ssm << "This type of var is not handled by MIP: " << *it << std::endl; ssm << " VarDecl flags (ti, bt, st, ot): " << ti->type().ti() << ti->type().bt() << ti->type().st() << ti->type().ot() << ", dim == " << ti->type().dim() << "\nRemove the variable or add a constraint so it is redefined." << std::endl; throw InternalError(ssm.str()); } double lb=0.0, ub=1.0; // for bool if (ti->domain()) { if (MIP_wrapper::VarType::REAL == vType) { FloatBounds fb = compute_float_bounds(getEnv()->envi(), it->e()->id()); if (fb.valid) { lb = fb.l.toDouble(); ub = fb.u.toDouble(); } else { lb = 1.0; ub = 0.0; } } else if (MIP_wrapper::VarType::INT == vType) { IntBounds ib = compute_int_bounds(getEnv()->envi(), it->e()->id()); if (ib.valid) { // Normally should be lb = static_cast(ib.l.toInt()); ub = static_cast(ib.u.toInt()); } else { lb = 1; ub = 0; } } } else if (MIP_wrapper::VarType::BINARY != vType) { lb = -getMIPWrapper()->getInfBound(); // if just 1 bound inf, using MZN's default? TODO ub = -lb; } // IntSetVal* dom = eval_intset(env,vdi->e()->ti()->domain()); // if (dom->size() > 1) // throw runtime_error("MIP_solverinstance: domains with holes ! supported, use --MIPdomains"); VarId res; Id* id = it->e()->id(); MZN_ASSERT_HARD( id == id->decl()->id() ); // Assume all unified MZN_ASSERT_HARD( it->e() == id->decl() ); // Assume all unified double obj = vd==objVd ? 1.0 : 0.0; auto decl00 = follow_id_to_decl( it->e() ); MZN_ASSERT_HARD ( decl00->isa() ); { auto vd00 = decl00->dyn_cast(); if ( 0!=vd00->e() ) { // Should be a const auto dRHS = exprToConst( vd00->e() ); lb = std::max( lb, dRHS ); ub = std::min( ub, dRHS ); } if ( it->e()!=vd00 ) { // A different vardecl res = exprToVar( vd00->id() ); // Assume FZN is sorted. MZN_ASSERT_HARD( !getMIPWrapper()->fPhase1Over ); // Still can change colUB, colObj /// Tighten the ini-expr's bounds lb = getMIPWrapper()->colLB.at( res ) = std::max( getMIPWrapper()->colLB.at( res ), lb ); ub = getMIPWrapper()->colUB.at( res ) = std::min( getMIPWrapper()->colUB.at( res ), ub ); if ( 0.0!=obj ) { getMIPWrapper()->colObj.at( res ) = obj; } } else { res = getMIPWrapper()->addVar(obj, lb, ub, vType, id->str().c_str()); } } /// Test infeasibility if ( lb>ub ) { _status = SolverInstance::UNSAT; if ( getMIPWrapper()->fVerbose ) std::cerr << " VarDecl '" << *(it->e()) << "' seems infeasible: computed bounds [" << lb << ", " << ub << ']' << std::endl; } if ( 0.0!=obj ) { dObjVarLB = lb; dObjVarUB = ub; getMIPWrapper()->output.nObjVarIndex = res; if ( getMIPWrapper()->fVerbose ) std::cerr << " MIP: objective variable index (0-based): " << res << std::endl; } _variableMap.insert(id, res); assert( res == _variableMap.get(id) ); } } if (mip_wrap->fVerbose && mip_wrap->sLitValues.size()) std::cerr << " MIP_solverinstance: during Phase 1, " << mip_wrap->nLitVars << " literals with " << mip_wrap-> sLitValues.size() << " values used." << std::endl; if (! getMIPWrapper()->fPhase1Over) getMIPWrapper()->addPhase1Vars(); if (mip_wrap->fVerbose) std::cerr << " MIP_solverinstance: adding constraints..." << std::flush; for (ConstraintIterator it = getEnv()->flat()->begin_constraints(); it != getEnv()->flat()->end_constraints(); ++it) { if (!it->removed()) { if (Call* c = it->e()->dyn_cast()) { _constraintRegistry.post(c); } } } if (mip_wrap->fVerbose) { std::cerr << " done, " << mip_wrap->getNRows() << " rows && " << mip_wrap->getNCols() << " columns in total."; if (mip_wrap->nIndicatorConstr) std::cerr << " " << mip_wrap->nIndicatorConstr << " indicator constraints." << std::endl; std::cerr << std::endl; if (mip_wrap->sLitValues.size()) std::cerr << " MIP_solverinstance: overall, " << mip_wrap->nLitVars << " literals with " << mip_wrap-> sLitValues.size() << " values used." << std::endl; } processSearchAnnotations( solveItem->ann() ); processWarmstartAnnotations( solveItem->ann() ); } // processFlatZinc template Expression* MIP_solverinstance::getSolutionValue(Id* id) { id = id->decl()->id(); if(id->type().isvar()) { MIP_solver::Variable var = exprToVar(id); double val = getMIPWrapper()->getValues()[var]; switch (id->type().bt()) { case Type::BT_INT: return IntLit::a(round_to_longlong(val)); case Type::BT_FLOAT: return FloatLit::a(val); case Type::BT_BOOL: return new BoolLit(Location(), round_to_longlong(val) != 0); default: return NULL; } } else { return id->decl()->e(); } } template void MIP_solverinstance::genCuts(const MIP_wrapper::Output& slvOut, MIP_wrapper::CutInput& cutsIn, bool fMIPSol) { for ( auto& pCG : cutGenerators ) { if ( !fMIPSol || pCG->getMask()&MIP_wrapper::MaskConsType_Lazy ) pCG->generate( slvOut, cutsIn ); } /// Select some most violated? TODO } template void MIP_solverinstance::printStatisticsLine(bool fLegend) { // auto nn = std::chrono::system_clock::now(); // auto n_c = std::chrono::system_clock::to_time_t( nn ); { std::ios oldState(nullptr); oldState.copyfmt(_log); _log.precision(12); _log << " % MIP Status: " << mip_wrap->getStatusName() << std::endl; if (fLegend) _log << " % obj, bound, time wall/CPU, nodes (left): "; _log << mip_wrap->getObjValue() << ", "; _log << mip_wrap->getBestBound() << ", "; _log.setf( std::ios::fixed ); _log.precision( 1 ); _log << mip_wrap->getWallTimeElapsed() << "/"; _log << mip_wrap->getCPUTime() << ", "; _log << mip_wrap->getNNodes(); if (mip_wrap->getNOpen()) _log << " ( " << mip_wrap->getNOpen() << " )"; // _log << " " << std::ctime( &n_c ); // ctime already adds EOL. os << endl; _log << std::endl; _log.copyfmt( oldState ); } } template void MIP_solverinstance::printStatistics(bool fLegend) { // auto nn = std::chrono::system_clock::now(); // auto n_c = std::chrono::system_clock::to_time_t( nn ); { EnvI& env = getEnv()->envi(); std::ios oldState(nullptr); oldState.copyfmt(env.outstream); env.outstream.precision(12); env.outstream << "%%%mzn-stat objective=" << mip_wrap->getObjValue() << std::endl;; env.outstream << "%%%mzn-stat objectiveBound=" << mip_wrap->getBestBound() << std::endl;; env.outstream << "%%%mzn-stat nodes=" << mip_wrap->getNNodes() << std::endl;; if (mip_wrap->getNOpen()) env.outstream << "%%%mzn-stat openNodes=" << mip_wrap->getNOpen() << std::endl;; env.outstream.setf( std::ios::fixed ); env.outstream.precision( 4 ); env.outstream << "%%%mzn-stat solveTime=" << mip_wrap->getWallTimeElapsed() << std::endl;; env.outstream.copyfmt( oldState ); env.outstream << "%%%mzn-stat-end" << std::endl; } } template void HandleSolutionCallback(const MIP_wrapper::Output& out, void* pp) { // multi-threading? TODO MIP_solverinstance* pSI = static_cast*>( pp ); assert(pSI); /// Not for -a: // if (fabs(pSI->lastIncumbent - out.objVal) > 1e-12*(1.0 + fabs(out.objVal))) { pSI->lastIncumbent = out.objVal; try { /// Sometimes the intermediate output is wrong, especially in SCIP pSI->printSolution(); // The solution in [out] is not used TODO } catch (const Exception& e) { std::cerr << std::endl; std::cerr << " Error when evaluating an intermediate solution: " << e.what() << ": " << e.msg() << std::endl; } catch (const std::exception& e) { std::cerr << std::endl; std::cerr << " Error when evaluating an intermediate solution: " << e.what() << std::endl; } catch (...) { std::cerr << std::endl; std::cerr << " Error when evaluating an intermediate solution: " << " UNKNOWN EXCEPTION." << std::endl; } // } } template void HandleCutCallback(const MIP_wrapper::Output& out, MIP_wrapper::CutInput& in, void* pp, bool fMIPSol) { // multi-threading? TODO MIP_solverinstance* pSI = static_cast*>( pp ); assert(pSI); assert(&out); assert(&in); pSI->genCuts( out, in, fMIPSol ); } template SolverInstance::Status MIP_solverinstance::solve(void) { SolveI* solveItem = getEnv()->flat()->solveItem(); int nProbType=0; if (solveItem->st() != SolveI::SolveType::ST_SAT) { if (solveItem->st() == SolveI::SolveType::ST_MAX) { getMIPWrapper()->setObjSense(1); getMIPWrapper()->setProbType(1); nProbType=1; if (mip_wrap->fVerbose) std::cerr << " MIP_solverinstance: this is a MAXimization problem." << std::endl; } else { getMIPWrapper()->setObjSense(-1); getMIPWrapper()->setProbType(-1); nProbType=-1; if (mip_wrap->fVerbose) std::cerr << " MIP_solverinstance: this is a MINimization problem." << std::endl; } if (mip_wrap->fVerbose) { std::cerr << " MIP_solverinstance: bounds for the objective function: " << dObjVarLB << ", " << dObjVarUB << std::endl; } } else { getMIPWrapper()->setProbType(0); if (mip_wrap->fVerbose) std::cerr << " MIP_solverinstance: this is a SATisfiability problem." << std::endl; } lastIncumbent = 1e200; // for callbacks MIP_wrapper::Status sw; if ( SolverInstance::UNSAT == _status ) // already deduced - exit now return _status; if ( getMIPWrapper()->getNCols() ) { // If any variables, we need to run solver just to get values? getMIPWrapper()->provideSolutionCallback(HandleSolutionCallback, this); if ( cutGenerators.size() ) // only then, can modify presolve getMIPWrapper()->provideCutCallback(HandleCutCallback, this); ////////////// clean up envi ///////////////// { /// Removing for now - need access to output variables TODO // cleanupForNonincrementalSolving(); if (GC::locked() && mip_wrap->fVerbose) std::cerr << "WARNING: GC is locked before SolverInstance::solve()! Wasting memory." << std::endl; // GCLock lock; GC::trigger(); } getMIPWrapper()->solve(); // printStatistics(cout, 1); MznSolver does this (if it wants) sw = getMIPWrapper()->getStatus(); } else { if ( mip_wrap->fVerbose ) std::cerr << " MIP_solverinstance: no constraints - skipping actual solution phase." << std::endl; sw = MIP_wrapper::Status::OPT; printSolution(); } SolverInstance::Status s = SolverInstance::UNKNOWN; switch(sw) { case MIP_wrapper::Status::OPT: if ( 0!=nProbType ) { s = SolverInstance::OPT; } else { s = SolverInstance::SAT; // For SAT problems, just say SAT unless we know it's complete } break; case MIP_wrapper::Status::SAT: s = SolverInstance::SAT; break; case MIP_wrapper::Status::UNSAT: s = SolverInstance::UNSAT; break; case MIP_wrapper::Status::UNBND: s = SolverInstance::UNBND; break; case MIP_wrapper::Status::UNSATorUNBND: s = SolverInstance::UNSATorUNBND; break; case MIP_wrapper::Status::UNKNOWN: s = SolverInstance::UNKNOWN; break; default: s = SolverInstance::ERROR; } return s; } namespace SCIPConstraints { bool CheckAnnUserCut(const Call* call); bool CheckAnnLazyConstraint(const Call* call); int GetMaskConsType(const Call* call); /// Create constraint name /// Input: a prefix, a counter, and the original call. /// If the call has a path annotation, that is used, /// otherwise pfx << cnt. inline std::string makeConstrName(const char* pfx, int cnt, const Expression* cOrig=nullptr) { Call* mznp; if (nullptr!=cOrig && (mznp=cOrig->ann().getCall(constants().ann.mzn_path))) { assert(1==mznp->n_args()); auto strp = mznp->arg(0)->dyn_cast(); assert(strp); return strp->v().str().substr(0, 255); // Gurobi 8.1 has <=255 characters } std::ostringstream ss; ss << pfx << cnt; return ss.str(); } /// Gurobi 8.1.0 complains about duplicates, CPLEX 12.8.0 just ignores repeats /// An example for duplicated indices was on 72a9b64f with two floats equated template void removeDuplicates(std::vector& rmi, std::vector& rmv) { std::unordered_map linExp; for (int i=rmi.size(); i--; ) linExp[rmi[i]] += rmv[i]; if (rmi.size()==linExp.size()) return; rmi.resize(linExp.size()); rmv.resize(linExp.size()); int i=0; for (const auto& iv: linExp) { rmi[i] = iv.first; rmv[i] = iv.second; ++i; } } template void p_lin(SolverInstanceBase& si, const Call* call, MIP_wrapper::LinConType lt) { MIP_solverinstance& gi = dynamic_cast&>( si ); Env& _env = gi.env(); // ArrayLit* al = eval_array_lit(_env.envi(), args[0]); // int nvars = al->v().size(); std::vector coefs; // gi.exprToArray(args[0], coefs); std::vector::VarId> vars; // gi.exprToVarArray(args[1], vars); IntVal ires; FloatVal fres; double rhs; if(call->arg(2)->type().isint()) { ires = eval_int(_env.envi(), call->arg(2)); rhs = static_cast(ires.toInt()); } else if(call->arg(2)->type().isfloat()) { fres = eval_float(_env.envi(), call->arg(2)); rhs = fres.toDouble(); } else { throw InternalError("p_lin: rhs unknown type"); } /// Process coefs & vars together to eliminate literals (problem with Gurobi's updatemodel()'s) ArrayLit* alC = eval_array_lit(_env.envi(), call->arg(0)); coefs.reserve(alC->size()); ArrayLit* alV = eval_array_lit(_env.envi(), call->arg(1)); vars.reserve(alV->size()); for (unsigned int i=0; isize(); i++) { const double dCoef = gi.exprToConst( (*alC)[i] ); if (Id* ident = (*alV)[i]->dyn_cast()) { coefs.push_back( dCoef ); vars.push_back( gi.exprToVar( ident ) ); } else rhs -= dCoef*gi.exprToConst( (*alV)[i] ); } assert(coefs.size() == vars.size()); /// Check feas-ty if ( coefs.empty() ) { if ( (MIP_wrapper::LinConType::EQ==lt && 1e-5 < fabs( rhs )) || (MIP_wrapper::LinConType::LQ==lt && -1e-5 > ( rhs )) || (MIP_wrapper::LinConType::GQ==lt && 1e-5 < ( rhs )) ) { si._status = SolverInstance::UNSAT; if ( gi.getMIPWrapper()->fVerbose ) std::cerr << " Constraint '" << *call << "' seems infeasible: simplified to 0 (rel) " << rhs << std::endl; } } else { removeDuplicates(vars, coefs); // See if the solver adds indexation itself: no. gi.getMIPWrapper()->addRow(static_cast(coefs.size()), &vars[0], &coefs[0], lt, rhs, GetMaskConsType(call), makeConstrName("p_lin_", (gi.getMIPWrapper()->nAddedRows++), call)); } } template void p_int_lin_le(SolverInstanceBase& si, const Call* call) { p_lin(si, call, MIP_wrapper::LQ); } template void p_int_lin_eq(SolverInstanceBase& si, const Call* call) { p_lin(si, call, MIP_wrapper::EQ); } template void p_float_lin_le(SolverInstanceBase& si, const Call* call) { p_lin(si, call, MIP_wrapper::LQ); } template void p_float_lin_eq(SolverInstanceBase& si, const Call* call) { p_lin(si, call, MIP_wrapper::EQ); } // The non-_lin constraints happen in a failed model || in a non-optimized one: template void p_non_lin(SolverInstanceBase& si, const Call* call, MIP_wrapper::LinConType nCmp) { MIP_solverinstance& gi = dynamic_cast&>( si ); std::vector coefs; std::vector vars; double rhs = 0.0; if ( call->arg(0)->isa() ) { coefs.push_back( 1.0 ); vars.push_back( gi.exprToVar(call->arg(0)) ); } else rhs -= gi.exprToConst(call->arg(0)); if ( call->arg(1)->isa() ) { coefs.push_back( -1.0 ); vars.push_back( gi.exprToVar(call->arg(1)) ); } else rhs += gi.exprToConst(call->arg(1)); /// Check feas-ty if ( coefs.empty() ) { if ( (MIP_wrapper::LinConType::EQ==nCmp && 1e-5 < fabs( rhs )) || (MIP_wrapper::LinConType::LQ==nCmp && -1e-5 > ( rhs )) || (MIP_wrapper::LinConType::GQ==nCmp && 1e-5 < ( rhs )) ) { si._status = SolverInstance::UNSAT; if ( gi.getMIPWrapper()->fVerbose ) std::cerr << " Constraint '" << *call << "' seems infeasible: simplified to 0 (rel) " << rhs << std::endl; } } else { removeDuplicates(vars, coefs); gi.getMIPWrapper()->addRow(static_cast(vars.size()), &vars[0], &coefs[0], nCmp, rhs, GetMaskConsType(call), makeConstrName("p_eq_", (gi.getMIPWrapper()->nAddedRows++), call)); } } template void p_eq(SolverInstanceBase& si, const Call* call) { p_non_lin( si, call, MIP_wrapper::EQ ); } template void p_le(SolverInstanceBase& si, const Call* call) { p_non_lin( si, call, MIP_wrapper::LQ ); } /// var1<=0 if var2==0 template void p_indicator_le0_if0(SolverInstanceBase& si, const Call* call) { MIP_solverinstance& gi = dynamic_cast&>( si ); /// Looking at the bounded variable and the flag bool f1const=0, f2const=0; double val1, val2; MIP_solver::Variable var1, var2; if ( call->arg(0)->isa() ) { var1 = gi.exprToVar(call->arg(0)); } else { f1const = 1; val1 = gi.exprToConst(call->arg(0)); } if ( call->arg(1)->isa() ) { var2 = gi.exprToVar(call->arg(1)); } else { f2const = 1; val2 = gi.exprToConst(call->arg(1)); } /// Check feas-ty. 1e-6 ????????????? TODO if ( f1const && f2const ) { if ( val1>1e-6 && val2<1e-6 ) { si._status = SolverInstance::UNSAT; if ( gi.getMIPWrapper()->fVerbose ) std::cerr << " Constraint '" << *call << "' seems infeasible: " << val2 << "==0 -> " << val1 << "<=0" << std::endl; } } else if ( f1const ) { if ( val1>1e-6 ) // so var2==1 gi.getMIPWrapper()->setVarBounds( var2, 1.0, 1.0 ); } else if ( f2const ) { if ( val2<1e-6 ) // so var1<=0 gi.getMIPWrapper()->setVarUB( var1, 0.0 ); } else { double coef = 1.0; gi.getMIPWrapper()->addIndicatorConstraint( var2, 0, 1, &var1, &coef, MIP_wrapper::LinConType::LQ, 0.0, makeConstrName("p_ind_", (gi.getMIPWrapper()->nAddedRows++), call)); ++gi.getMIPWrapper()->nIndicatorConstr; } } /// var1==var2 if var3==1 template void p_indicator_eq_if1(SolverInstanceBase& si, const Call* call) { MIP_solverinstance& gi = dynamic_cast&>( si ); std::vector coefs; std::vector vars; double rhs = 0.0; /// Looking at the bounded variables and the flag bool f1const=0, f2const=0, fBconst=0; double val1, val2, valB; MIP_solver::Variable var1, var2, varB; if ( call->arg(0)->isa() ) { var1 = gi.exprToVar(call->arg(0)); coefs.push_back( 1.0 ); vars.push_back( var1 ); } else { f1const = 1; val1 = gi.exprToConst(call->arg(0)); rhs -= val1; } if ( call->arg(1)->isa() ) { var2 = gi.exprToVar(call->arg(1)); coefs.push_back( -1.0 ); vars.push_back( var2 ); } else { f2const = 1; val2 = gi.exprToConst(call->arg(1)); rhs += val2; } if ( call->arg(2)->isa() ) { varB = gi.exprToVar(call->arg(2)); } else { fBconst = 1; valB = gi.exprToConst(call->arg(2)); } /// Check feas-ty. 1e-6 ????????????? TODO if ( f1const && f2const && fBconst ) { if ( fabs(val1-val2)>1e-6 && val2>0.999999 ) { si._status = SolverInstance::UNSAT; if ( gi.getMIPWrapper()->fVerbose ) std::cerr << " Constraint '" << *call << "' seems infeasible: " << valB << "==0 -> " << val1 << "==" << val2 << std::endl; } } else if ( f1const && f2const ) { if ( fabs(val1-val2)>1e-6 ) // so varB=0 gi.getMIPWrapper()->setVarBounds( varB, 0.0, 0.0 ); } else if ( fBconst ) { if ( val2>0.999999 ) { // so var1<=0 removeDuplicates(vars, coefs); gi.getMIPWrapper()->addRow(static_cast(vars.size()), &vars[0], &coefs[0], MIP_wrapper::LinConType::EQ, rhs, MIP_wrapper::MaskConsType_Normal, makeConstrName("p_eq_", (gi.getMIPWrapper()->nAddedRows++), call)); } } else { std::ostringstream ss; ss << "p_ind_" << (gi.getMIPWrapper()->nAddedRows++); gi.getMIPWrapper()->addIndicatorConstraint( varB, 1, static_cast(coefs.size()), vars.data(), coefs.data(), MIP_wrapper::LinConType::EQ, rhs, makeConstrName("p_ind_", (gi.getMIPWrapper()->nAddedRows++), call)); ++gi.getMIPWrapper()->nIndicatorConstr; } } /// Cumulative template void p_cumulative(SolverInstanceBase& si, const Call* call) { MIP_solverinstance& gi = dynamic_cast&>( si ); std::unique_ptr pCG( new SECCutGen( gi.getMIPWrapper() ) ); assert( call->n_args()==4 ); std::vector startTimes; gi.exprToVarArray(call->arg(0), startTimes); std::vector durations, demands; gi.exprToArray(call->arg(1), durations); gi.exprToArray(call->arg(2), demands); double b = gi.exprToConst(call->arg(3)); gi.getMIPWrapper()->addCumulative(startTimes.size(), startTimes.data(), durations.data(), demands.data(), b, makeConstrName("p_cumulative_", (gi.getMIPWrapper()->nAddedRows++), call)); } /// The XBZ cut generator template void p_XBZ_cutgen(SolverInstanceBase& si, const Call* call) { MIP_solverinstance& gi = dynamic_cast&>( si ); // auto pCG = make_unique(); std::unique_ptr pCG( new XBZCutGen( gi.getMIPWrapper() ) ); assert( call->n_args()==3 ); gi.exprToVarArray(call->arg(0), pCG->varX); gi.exprToVarArray(call->arg(1), pCG->varB); assert(pCG->varX.size() == pCG->varB.size()); pCG->varZ = gi.exprToVar(call->arg(2)); // cout << " NEXT_CUTGEN" << endl; // pCG->print( cout ); gi.registerCutGenerator( move( pCG ) ); } /// Initialize the SEC cut generator template void p_SEC_cutgen(SolverInstanceBase& si, const Call* call) { MIP_solverinstance& gi = dynamic_cast&>( si ); std::unique_ptr pCG( new SECCutGen( gi.getMIPWrapper() ) ); assert( call->n_args()==1 ); gi.exprToVarArray(call->arg(0), pCG->varXij); // WHAT ABOUT CONSTANTS? const double dN = sqrt( pCG->varXij.size() ); MZN_ASSERT_HARD( fabs( dN - round(dN) ) < 1e-6 ); // should be a square matrix pCG->nN = round(dN); const auto sVld = pCG->validate(); MZN_ASSERT_HARD_MSG(sVld.empty(), "ERROR(s): " << sVld); // cout << " NEXT_CUTGEN" << endl; // pCG->print( cout ); gi.registerCutGenerator( move( pCG ) ); } /// SCIP's bound disj template void p_bounds_disj(SolverInstanceBase& si, const Call* call) { MIP_solverinstance& gi = dynamic_cast&>( si ); assert(6==call->n_args()); std::vector fUB, fUBF, bnd, bndF; std::vector vars, varsF; gi.exprToArray(call->arg(0), fUB); gi.exprToArray(call->arg(3), fUBF); gi.exprToArray(call->arg(1), bnd); gi.exprToArray(call->arg(4), bndF); gi.exprToVarArray(call->arg(2), vars); gi.exprToVarArray(call->arg(5), varsF); double coef = 1.0; gi.getMIPWrapper()->addBoundsDisj( fUB.size(), fUB.data(), bnd.data(), vars.data(), fUBF.size(), fUBF.data(), bndF.data(), varsF.data(), makeConstrName("p_bounds_disj_", (gi.getMIPWrapper()->nAddedRows++), call)); } } template void MIP_solverinstance::registerConstraints() { GCLock lock; _constraintRegistry.add("int2float", SCIPConstraints::p_eq); _constraintRegistry.add("bool_eq", SCIPConstraints::p_eq); // for inconsistency reported in fzn _constraintRegistry.add("int_eq", SCIPConstraints::p_eq); _constraintRegistry.add("int_le", SCIPConstraints::p_le); _constraintRegistry.add("int_lin_eq", SCIPConstraints::p_int_lin_eq); _constraintRegistry.add("int_lin_le", SCIPConstraints::p_int_lin_le); // _constraintRegistry.add("int_plus", SCIPConstraints::p_plus); // _constraintRegistry.add("bool2int", SCIPConstraints::p_eq); _constraintRegistry.add("float_eq", SCIPConstraints::p_eq); _constraintRegistry.add("float_le", SCIPConstraints::p_le); _constraintRegistry.add("float_lin_eq", SCIPConstraints::p_float_lin_eq); _constraintRegistry.add("float_lin_le", SCIPConstraints::p_float_lin_le); // _constraintRegistry.add("float_plus", SCIPConstraints::p_plus); /// Indicators, if supported by the solver _constraintRegistry.add("aux_int_le_zero_if_0__IND", SCIPConstraints::p_indicator_le0_if0); _constraintRegistry.add("aux_float_le_zero_if_0__IND", SCIPConstraints::p_indicator_le0_if0); _constraintRegistry.add("aux_float_eq_if_1__IND", SCIPConstraints::p_indicator_eq_if1); _constraintRegistry.add("fzn_cumulative", SCIPConstraints::p_cumulative); /// XBZ cut generator _constraintRegistry.add("array_var_float_element__XBZ_lb__cutgen", SCIPConstraints::p_XBZ_cutgen); _constraintRegistry.add("circuit__SECcuts", SCIPConstraints::p_SEC_cutgen); _constraintRegistry.add("bounds_disj", SCIPConstraints::p_bounds_disj); } } libminizinc-2.4.2/include/minizinc/solvers/MIP/MIP_wrap.hh000066400000000000000000000275761360574160400234410ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MIP_WRAPPER__ #define __MIP_WRAPPER__ #include //#include #include #include #include #include #include #include /// Facilitate lhs computation of a cut inline double computeSparse( int n, const int* ind, const double* coef, const double* dense, int nVarsDense ) { assert( ind && coef && dense ); double val=0.0; for ( int i=0; i=0 ); assert( ind[i] colObj, colLB, colUB; std::vector colTypes; std::vector colNames; // , rowLB, rowUB, elements; // veci whichInt // , starts, column; // double objUB; // double qpu; public: /// Parameter bool fVerbose = false; int nProbType = -2; // +-1: max/min; 0: sat public: struct Output { Status status; std::string statusName="Untouched"; double objVal = 1e308; double bestBound = 1e308; int nCols = 0; int nObjVarIndex=-1; const double *x = 0; int nNodes=0; int nOpenNodes=0; double dWallTime = 0.0; std::chrono::time_point dWallTime0; double dCPUTime = 0; std::clock_t cCPUTime0 = 0; }; Output output; /// General cut definition, could be used for addRow() too class CutDef { CutDef() { } public: CutDef( LinConType s, int m ) : sense( s ), mask( m ) { } std::vector rmatind; std::vector rmatval; LinConType sense=LQ; double rhs=0.0; int mask = 0; // need to know what type of cuts are registered before solve() TODO std::string rowName = ""; void addVar( int i, double c ) { rmatind.push_back( i ); rmatval.push_back( c ); } double computeViol( const double* x, int nCols ) { double lhs = computeSparse( static_cast(rmatind.size()), rmatind.data(), rmatval.data(), x, nCols ); if ( LQ==sense ) { return lhs-rhs; } else if ( GQ==sense ) { return rhs-lhs; } else assert( 0 ); return 0.0; } }; /// Cut callback fills one typedef std::vector CutInput; public: /// solution callback handler, the wrapper might not have these callbacks implemented typedef void (*SolCallbackFn)(const Output& , void* ); /// cut callback handler, the wrapper might not have these callbacks implemented typedef void (*CutCallbackFn)(const Output& , CutInput& , void* , bool fMIPSol // if with a MIP feas sol - lazy cuts only ); struct CBUserInfo { MIP_wrapper* wrapper = 0; MIP_wrapper::Output* pOutput=0; MIP_wrapper::Output* pCutOutput=0; void *psi=0; // external info. Intended to keep MIP_solverinstance SolCallbackFn solcbfn=0; CutCallbackFn cutcbfn=0; /// Union of all flags used for the registered callback cuts /// See MaskConstrType_.. /// Solvers need to know this /// In MIP_solverinstance, class CutGen defines getMask() which should return that int cutMask = 0; // can be any combination of User/Lazy bool fVerb = false; // used in Gurobi bool printed = false; // whether any solution was output double nTimeoutFeas = -1.0; // >=0 => stop that long after 1st feas double nTime1Feas = -1e100; // time of the 1st feas }; CBUserInfo cbui; public: MIP_wrapper() { cbui.wrapper = this; } virtual ~MIP_wrapper() { /* cleanup(); */ } /// derived should overload and call the ancestor // virtual void cleanup() { // colObj.clear(); colLB.clear(); colUB.clear(); // colTypes.clear(); colNames.clear(); // } /// re-create solver object. Called from the base class constructor // virtual void resetModel() { }; // virtual void printVersion(ostream& os) { os << "Abstract MIP wrapper"; } // virtual void printHelp(ostream& ) { } public: bool fPhase1Over = false; private: /// adding a variable just internally (in Phase 1 only that). Not to be used directly. virtual VarId addVarLocal(double obj, double lb, double ub, VarType vt, std::string name="") { // cerr << " addVarLocal: colObj.size() == " << colObj.size() // << " obj == " <(colObj.size()-1); } /// add the given var to the solver. Asserts all previous are added. Phase >=2. No direct use virtual void addVar(int j) { assert(j == getNCols()); assert(fPhase1Over); doAddVars(1, &colObj[j], &colLB[j], &colUB[j], &colTypes[j], &colNames[j]); } /// actual adding new variables to the solver. "Updates" the model (e.g., Gurobi). No direct use virtual void doAddVars(size_t n, double *obj, double *lb, double *ub, VarType *vt, std::string *names) = 0; public: /// debugging stuff // set sLitValues; std::unordered_map sLitValues; void setProbType( int t ) { nProbType=t; } /// adding a variable, at once to the solver, this is for the 2nd phase virtual VarId addVar(double obj, double lb, double ub, VarType vt, std::string name="") { // cerr << " AddVar: " << lb << ": "; VarId res = addVarLocal(obj, lb, ub, vt, name); if (fPhase1Over) addVar(res); return res; } int nLitVars=0; /// adding a literal as a variable. Should not happen in feasible models virtual VarId addLitVar(double v) { // Cannot do this: at least CBC does not support duplicated indexes TODO?? // ++nLitVars; // auto itFound = sLitValues.find(v); // if (sLitValues.end() != itFound) // return itFound->second; std::ostringstream oss; oss << "lit_" << v << "__" << (nLitVars++); std::string name = oss.str(); size_t pos = name.find('.'); if (std::string::npos != pos) name.replace(pos, 1, "p"); VarId res = addVarLocal(0.0, v, v, REAL, name); if (fPhase1Over) addVar(res); // cerr << " AddLitVar " << v << " (PROBABLY WRONG)" << endl; sLitValues[v] = res; return res; } /// adding all local variables upfront. Makes sure it's called only once virtual void addPhase1Vars() { assert(0 == getNColsModel()); assert(! fPhase1Over); if (fVerbose) std::cerr << " MIP_wrapper: adding the " << colObj.size() << " Phase-1 variables..." << std::flush; doAddVars(colObj.size(), &colObj[0], &colLB[0], &colUB[0], &colTypes[0], &colNames[0]); if (fVerbose) std::cerr << " done." << std::endl; fPhase1Over = true; // SCIP needs after adding } /// var bounds virtual void setVarBounds( int iVar, double lb, double ub ) { throw 0; } virtual void setVarLB( int iVar, double lb ) { throw 0; } virtual void setVarUB( int iVar, double ub ) { throw 0; } /// adding a linear constraint virtual void addRow(int nnz, int *rmatind, double* rmatval, LinConType sense, double rhs, int mask = MaskConsType_Normal, std::string rowName = "") = 0; /// Indicator constraint: x[iBVar]==bVal -> lin constr virtual void addIndicatorConstraint(int iBVar, int bVal, int nnz, int *rmatind, double* rmatval, LinConType sense, double rhs, std::string rowName = "") { throw std::runtime_error("Indicator constraints not supported. "); } /// Bounds disj for SCIP virtual void addBoundsDisj(int n, double *fUB, double *bnd, int* vars, int nF, double *fUBF, double *bndF, int* varsF, std::string rowName = "") { throw std::runtime_error("Bounds disjunctions not supported. "); } /// Cumulative, currently SCIP only virtual void addCumulative(int nnz, int *rmatind, double* d, double* r, double b, std::string rowName="") { throw std::runtime_error("Cumulative constraints not supported. "); } /// 0: model-defined level, 1: free, 2: uniform search virtual int getFreeSearch() { return 1; } /// Return 0 if ignoring searches virtual bool addSearch( const std::vector& vars, const std::vector pri ) { return false; } /// Return 0 if ignoring warm starts virtual bool addWarmStart( const std::vector& vars, const std::vector vals ) { return false; } int nAddedRows = 0; // for name counting int nIndicatorConstr = 0; /// adding an implication // virtual void addImpl() = 0; virtual void setObjSense(int s) = 0; // +/-1 for max/min virtual double getInfBound() = 0; virtual int getNCols() = 0; virtual int getNColsModel() { return getNCols(); } // from the solver virtual int getNRows() = 0; // void setObjUB(double ub) { objUB = ub; } // void addQPUniform(double c) { qpu = c; } // also sets problem type to MIQP unless c=0 /// Set solution callback. Thread-safety?? /// solution callback handler, the wrapper might not have these callbacks implemented virtual void provideSolutionCallback(SolCallbackFn cbfn, void* info) { assert(cbfn); cbui.pOutput = &output; cbui.psi = info; cbui.solcbfn = cbfn; } /// solution callback handler, the wrapper might not have these callbacks implemented virtual void provideCutCallback(CutCallbackFn cbfn, void* info) { assert(cbfn); cbui.pCutOutput = 0; // &outpCuts; thread-safety: caller has to provide this cbui.psi = info; cbui.cutcbfn = cbfn; } virtual void solve() = 0; /// OUTPUT, should also work in a callback virtual const double* getValues() = 0; virtual double getObjValue() = 0; virtual double getBestBound() = 0; virtual double getWallTimeElapsed() { return output.dWallTime; } virtual double getCPUTime() = 0; virtual Status getStatus() = 0; virtual std::string getStatusName() = 0; virtual int getNNodes() = 0; virtual int getNOpen() = 0; /// Default MZN library for MIP static std::string getMznLib(); }; #endif // __MIP_WRAPPER__ libminizinc-2.4.2/include/minizinc/solvers/MIP/MIP_xpress_solverfactory.hh000066400000000000000000000010751360574160400267600ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_MIP_XPRESS_SOLVERFACTORY_HH__ #define __MINIZINC_MIP_XPRESS_SOLVERFACTORY_HH__ namespace MiniZinc { class Xpress_SolverFactoryInitialiser { public: Xpress_SolverFactoryInitialiser(void); }; } #endif libminizinc-2.4.2/include/minizinc/solvers/MIP/MIP_xpress_wrap.hh000066400000000000000000000071101360574160400250230ustar00rootroot00000000000000/* * Main authors: * Karsten Lehmann */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MIP_XPRESS_WRAPPER_H__ #define __MIP_XPRESS_WRAPPER_H__ #include "minizinc/solvers/MIP/MIP_wrap.hh" #include #include "xprb_cpp.h" #include "xprs.h" using namespace std; using namespace dashoptimization; class MIP_xpress_wrapper : public MIP_wrapper { public: class Options : public MiniZinc::SolverInstanceBase::Options { public: int msgLevel = 0; int timeout = 0; int numSolutions = 0; std::string logFile = ""; std::string writeModelFile = ""; std::string writeModelFormat = "lp"; double absGap = 0; double relGap = 0.0001; bool printAllSolutions = false; bool processOption(int& i, std::vector& argv); static void printHelp(std::ostream& ); }; private: Options* options=nullptr; public: public: virtual void doAddVars(size_t n, double *obj, double *lb, double *ub, VarType *vt, string *names); virtual void addRow(int nnz, int *rmatind, double *rmatval, LinConType sense, double rhs, int mask = MaskConsType_Normal, string rowName = ""); virtual void setObjSense(int s); virtual void solve(); virtual void setVarLB(int iVar, double lb); virtual void setVarUB(int iVar, double ub); virtual void setVarBounds(int iVar, double lb, double ub); virtual void addIndicatorConstraint(int iBVar, int bVal, int nnz, int *rmatind, double *rmatval, LinConType sense, double rhs, std::string rowName = ""); virtual bool addWarmStart(const std::vector &vars, const std::vector vals); virtual int getNCols() {return variables.size();} virtual int getNRows() {return nRows;} virtual double getInfBound() { return XPRB_INFINITY; } virtual const double *getValues() { return output.x; } virtual double getObjValue() { return output.objVal; } virtual double getBestBound() { return output.bestBound; } virtual double getCPUTime() { return output.dCPUTime; } virtual Status getStatus() { return output.status; } virtual string getStatusName() { return output.statusName; } virtual int getNNodes() { return output.nNodes; } virtual int getNOpen() { return output.nOpenNodes; } MIP_xpress_wrapper(Options* opt) : options(opt) {} virtual ~MIP_xpress_wrapper() {} static std::string getDescription(MiniZinc::SolverInstanceBase::Options* opt=NULL); static std::string getVersion(MiniZinc::SolverInstanceBase::Options* opt=NULL); static std::string getId(void); static std::string getName(void); static std::vector getTags(void); static std::vector getStdFlags(void); static std::string needDllFlag(void); private: XPRBprob problem{}; XPRBexpr xpressObj{}; vector variables{}; size_t nRows{0}; void setUserSolutionCallback(); void setOptions(); void writeModelIfRequested(); int convertConstraintType(LinConType sense); int convertVariableType(VarType varType); int convertObjectiveSense(int s); XPRBctr addConstraint(int nnz, int *rmatind, double *rmatval, LinConType sense, double rhs, int mask, string rowName); void addDummyConstraint(); }; #endif // __MIP_XPRESS_WRAPPER_H__ libminizinc-2.4.2/include/minizinc/solvers/fzn_solverfactory.hh000066400000000000000000000010531360574160400250730ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_FZN_SOLVERFACTORY_HH__ #define __MINIZINC_FZN_SOLVERFACTORY_HH__ namespace MiniZinc { class FZN_SolverFactoryInitialiser { public: FZN_SolverFactoryInitialiser(void); }; } #endif libminizinc-2.4.2/include/minizinc/solvers/fzn_solverinstance.hh000066400000000000000000000047101360574160400252330ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_FZN_SOLVER_INSTANCE_HH__ #define __MINIZINC_FZN_SOLVER_INSTANCE_HH__ #include #include //#include namespace MiniZinc { class FZNSolverOptions : public SolverInstanceBase::Options { public: std::string fzn_solver; std::string backend; std::vector fzn_flags; int numSols = 1; bool allSols = false; std::string parallel; int fzn_time_limit_ms = 0; int solver_time_limit_ms = 0; bool fzn_sigint = false; bool fzn_needs_paths = false; bool fzn_output_passthrough = false; bool supports_a = false; bool supports_n = false; bool supports_f = false; bool supports_p = false; bool supports_s = false; bool supports_r = false; bool supports_v = false; bool supports_t = false; std::vector fzn_solver_flags; }; class FZNSolverInstance : public SolverInstanceBase { private: std::string _fzn_solver; protected: Model* _fzn; Model* _ozn; public: FZNSolverInstance(Env& env, std::ostream& log, SolverInstanceBase::Options* opt); ~FZNSolverInstance(void); Status next(void) {return SolverInstance::ERROR;} Status solve(void); void processFlatZinc(void); void resetSolver(void); protected: Expression* getSolutionValue(Id* id); }; class FZN_SolverFactory: public SolverFactory { protected: virtual SolverInstanceBase* doCreateSI(Env& env, std::ostream& log, SolverInstanceBase::Options* opt); public: FZN_SolverFactory(void); virtual SolverInstanceBase::Options* createOptions(void); virtual std::string getDescription(SolverInstanceBase::Options* opt=NULL); virtual std::string getVersion(SolverInstanceBase::Options* opt=NULL); virtual std::string getId(void); virtual bool processOption(SolverInstanceBase::Options* opt, int& i, std::vector& argv); virtual void printHelp(std::ostream& os); void setAcceptedFlags(SolverInstanceBase::Options* opt, const std::vector& flags); }; } #endif libminizinc-2.4.2/include/minizinc/solvers/geas/000077500000000000000000000000001360574160400217135ustar00rootroot00000000000000libminizinc-2.4.2/include/minizinc/solvers/geas/geas_constraints.hh000066400000000000000000000111631360574160400256040ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Jip J. Dekker */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_GEAS_CONSTRAINTS_HH__ #define __MINIZINC_GEAS_CONSTRAINTS_HH__ #include #include namespace MiniZinc { namespace GeasConstraints { #define PosterImpl(X) void X(SolverInstanceBase& s, const Call* ce) /* Integer Comparison Constraints */ PosterImpl(p_int_eq); PosterImpl(p_int_ne); PosterImpl(p_int_le); PosterImpl(p_int_lt); PosterImpl(p_int_eq_imp); PosterImpl(p_int_ne_imp); PosterImpl(p_int_le_imp); PosterImpl(p_int_lt_imp); PosterImpl(p_int_eq_reif); PosterImpl(p_int_ne_reif); PosterImpl(p_int_le_reif); PosterImpl(p_int_lt_reif); /* Integer Arithmetic Constraints */ PosterImpl(p_int_abs); PosterImpl(p_int_times); PosterImpl(p_int_div); PosterImpl(p_int_max); PosterImpl(p_int_min); /* Integer Linear Constraints */ PosterImpl(p_int_lin_eq); PosterImpl(p_int_lin_ne); PosterImpl(p_int_lin_le); PosterImpl(p_int_lin_eq_imp); PosterImpl(p_int_lin_ne_imp); PosterImpl(p_int_lin_le_imp); PosterImpl(p_int_lin_eq_reif); PosterImpl(p_int_lin_ne_reif); PosterImpl(p_int_lin_le_reif); /* Boolean Comparison Constraints */ PosterImpl(p_bool_eq); PosterImpl(p_bool_ne); PosterImpl(p_bool_le); PosterImpl(p_bool_lt); PosterImpl(p_bool_eq_imp); PosterImpl(p_bool_ne_imp); PosterImpl(p_bool_le_imp); PosterImpl(p_bool_lt_imp); PosterImpl(p_bool_eq_reif); PosterImpl(p_bool_ne_reif); PosterImpl(p_bool_le_reif); PosterImpl(p_bool_lt_reif); /* Boolean Arithmetic Constraints */ PosterImpl(p_bool_or) ; PosterImpl(p_bool_and); PosterImpl(p_bool_xor); PosterImpl(p_bool_not); PosterImpl(p_bool_or_imp); PosterImpl(p_bool_and_imp); PosterImpl(p_bool_xor_imp); PosterImpl(p_bool_clause); PosterImpl(p_array_bool_or); PosterImpl(p_array_bool_and); PosterImpl(p_bool_clause_imp); PosterImpl(p_array_bool_or_imp); PosterImpl(p_array_bool_and_imp); PosterImpl(p_bool_clause_reif); /* Boolean Linear Constraints */ PosterImpl(p_bool_lin_eq); PosterImpl(p_bool_lin_ne); PosterImpl(p_bool_lin_le); PosterImpl(p_bool_lin_eq_imp); PosterImpl(p_bool_lin_ne_imp); PosterImpl(p_bool_lin_le_imp); PosterImpl(p_bool_lin_lt_imp); PosterImpl(p_bool_lin_eq_reif); PosterImpl(p_bool_lin_ne_reif); PosterImpl(p_bool_lin_le_reif); /* Coercion Constraints */ PosterImpl(p_bool2int); /* Element Constraints */ PosterImpl(p_array_int_element); PosterImpl(p_array_bool_element); PosterImpl(p_array_int_maximum); PosterImpl(p_array_int_minimum); PosterImpl(p_array_var_int_element); PosterImpl(p_array_var_bool_element); /* Global Constraints */ PosterImpl(p_all_different); PosterImpl(p_all_different_except_0); PosterImpl(p_at_most); PosterImpl(p_at_most1); PosterImpl(p_cumulative); PosterImpl(p_disjunctive); PosterImpl(p_global_cardinality); PosterImpl(p_table_int); /**** NOT YET SUPPORTED: ****/ /* Boolean Arithmetic Constraints */ // PosterImpl(p_array_bool_xor); // PosterImpl(p_array_bool_xor_imp); /* Floating Point Comparison Constraints */ // PosterImpl(p_float_eq); // PosterImpl(p_float_ne); // PosterImpl(p_float_le); // PosterImpl(p_float_lt); // PosterImpl(p_float_eq_reif); // PosterImpl(p_float_le_reif) // PosterImpl(p_float_lt_reif); /* Floating Point Arithmetic Constraints */ // PosterImpl(p_float_times); // PosterImpl(p_float_div); // PosterImpl(p_float_plus) ; // PosterImpl(p_float_sqrt); // PosterImpl(p_float_abs);; // PosterImpl(p_float_max); // PosterImpl(p_float_min); // PosterImpl(p_float_acos); // PosterImpl(p_float_asin); // PosterImpl(p_float_atan); // PosterImpl(p_float_cos); // PosterImpl(p_float_exp); // PosterImpl(p_float_sin); // PosterImpl(p_float_tan); // PosterImpl(p_float_ln); // PosterImpl(p_float_log10); // PosterImpl(p_float_log2); /* Floating Linear Constraints */ // PosterImpl(p_float_lin_eq); // PosterImpl(p_float_lin_eq_reif); // PosterImpl(p_float_lin_le); // PosterImpl(p_float_lin_le_reif); /* Coercion Constraints */ // PosterImpl(p_int2float); } } #endif // __MINIZINC_GEAS_CONSTRAINTS_HH__libminizinc-2.4.2/include/minizinc/solvers/geas_solverfactory.hh000066400000000000000000000011201360574160400252100ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Jip J. Dekker */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_GEAS_SOLVERFACTORY_HH__ #define __MINIZINC_GEAS_SOLVERFACTORY_HH__ namespace MiniZinc { class Geas_SolverFactoryInitialiser { public: Geas_SolverFactoryInitialiser(); }; } #endif // __MINIZINC_GEAS_SOLVERFACTORY_HH__ libminizinc-2.4.2/include/minizinc/solvers/geas_solverinstance.hh000066400000000000000000000101671360574160400253600ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Jip J. Dekker */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_GEAS_SOLVER_INSTANCE_HH__ #define __MINIZINC_GEAS_SOLVER_INSTANCE_HH__ #include #include #include namespace MiniZinc { class GeasOptions : public SolverInstanceBase::Options { public: bool all_solutions = false; int conflicts = 0; bool free_search = false; int nr_solutions = 1; int obj_probe_limit = 0; bool statistics = false; std::chrono::milliseconds time = std::chrono::milliseconds(0); }; class GeasVariable { public: enum Type {BOOL_TYPE, FLOAT_TYPE, INT_TYPE}; protected: Type _t; // Type of the variable union { geas::patom_t _bv; geas::fp::fpvar _fv; geas::intvar _iv; }; public: explicit GeasVariable(const geas::patom_t& bv) : _t(BOOL_TYPE), _bv(bv) {}; explicit GeasVariable(const geas::fp::fpvar& fv) : _t(FLOAT_TYPE), _fv(fv) {}; explicit GeasVariable(const geas::intvar &iv) : _t(INT_TYPE), _iv(iv) {}; GeasVariable(const GeasVariable& gv) : _t(gv._t) { switch (_t) { case BOOL_TYPE: _bv = gv._bv; break; case FLOAT_TYPE: _fv = gv._fv; break; case INT_TYPE: _iv = gv._iv; break; } } bool isBool() const { return _t == BOOL_TYPE; } bool isFloat() const { return _t == FLOAT_TYPE; } bool isInt() const { return _t == INT_TYPE; } geas::patom_t boolVar() { return _bv; } geas::fp::fpvar floatVar() { return _fv; } geas::intvar intVar() { return _iv; } }; class GeasTypes { public: typedef GeasVariable Variable; typedef MiniZinc::Statistics Statistics; }; class GeasSolverInstance : public SolverInstanceImpl { public: GeasSolverInstance(Env& env, std::ostream& log, SolverInstanceBase::Options* opt); ~GeasSolverInstance() override = default; void processFlatZinc() override; geas::solver_data* solver_data() { return _solver.data; } geas::solver& solver() { return _solver; } Status solve() override; Status next() override { return SolverInstance::ERROR; } // TODO: Implement void resetSolver() override; Expression* getSolutionValue(Id* id) override; void printStatistics(bool fLegend) override; // MiniZinc to Geas conversions bool asBool(Expression* e) { return eval_bool(env().envi(), e); } vec asBool(ArrayLit* al); geas::patom_t asBoolVar(Expression* e); vec asBoolVar(ArrayLit* al); vec asInt(ArrayLit* al); int asInt(Expression* e) { return static_cast(eval_int(env().envi(), e).toInt()); } geas::intvar asIntVar(Expression* e); vec asIntVar(ArrayLit* al); // TODO: create only when necessary or use Geas internal geas::intvar zero; protected: geas::solver _solver; Model* _flat; SolveI::SolveType _obj_type = SolveI::ST_SAT; std::unique_ptr _obj_var; GeasTypes::Variable& resolveVar(Expression* e); bool addSolutionNoGood(); void registerConstraint(std::string name, poster p); void registerConstraints(); }; class Geas_SolverFactory: public SolverFactory { public: Geas_SolverFactory(); SolverInstanceBase::Options* createOptions() override; SolverInstanceBase* doCreateSI(Env& env, std::ostream& log, SolverInstanceBase::Options* opt) override; std::string getDescription(SolverInstanceBase::Options* opt) override { return "Elsie Geas - Another Lazy Clause Generation Solver"; }; std::string getVersion(SolverInstanceBase::Options* opt) override { return "0.0.1"; } std::string getId() override { return "org.minizinc.geas"; } bool processOption(SolverInstanceBase::Options* opt, int& i, std::vector& argv) override; void printHelp(std::ostream& os) override; }; } #endif // __MINIZINC_GEAS_SOLVER_INSTANCE_HH__ libminizinc-2.4.2/include/minizinc/solvers/gecode/000077500000000000000000000000001360574160400222225ustar00rootroot00000000000000libminizinc-2.4.2/include/minizinc/solvers/gecode/fzn_space.hh000066400000000000000000000064361360574160400245240ustar00rootroot00000000000000/* * Main authors: * Kevin Leo * Andrea Rendl * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_GECODE_FZN_SPACE_HH__ #define __MINIZINC_GECODE_FZN_SPACE_HH__ #include #include #include #ifdef GECODE_HAS_SET_VARS #include #endif #ifdef GECODE_HAS_FLOAT_VARS #include #endif #include namespace MiniZinc { class FznSpace : public Gecode::Space { public: /// The integer variables std::vector iv; /// The introduced integer variables Gecode::IntVarArray iv_aux; /// Indicates whether an integer variable is introduced by mzn2fzn std::vector iv_introduced; /// Indicates whether an integer variable is defined std::vector iv_defined; /// The Boolean variables std::vector bv; /// The introduced Boolean variables Gecode::BoolVarArray bv_aux; /// Indicates whether a Boolean variable is introduced by mzn2fzn std::vector bv_introduced; /// Indicates whether a Boolean variable is defined std::vector bv_defined; #ifdef GECODE_HAS_SET_VARS /// The set variables std::vector sv; /// The introduced set variables Gecode::SetVarArray sv_aux; /// Indicates whether a set variable is introduced by mzn2fzn std::vector sv_introduced; /// Indicates whether a set variable is introduced by mzn2fzn std::vector sv_defined; #endif #ifdef GECODE_HAS_FLOAT_VARS /// The float variables std::vector fv; /// The introduced float variables Gecode::FloatVarArray fv_aux; /// Indicates whether a float variable is introduced by mzn2fzn std::vector fv_introduced; /// Indicates whether a float variable is defined std::vector fv_defined; #endif /// Indicates if the objective variable is integer (float otherwise) bool _optVarIsInt; /// Index of the variable to optimize int _optVarIdx; /// Whether the introduced variables still need to be copied bool _copyAuxVars; /// solve type (SAT, MIN or MAX) MiniZinc::SolveI::SolveType _solveType; /// copy constructor FznSpace(FznSpace&); /// standard constructor FznSpace(void) : _optVarIsInt(true), _optVarIdx(-1), _copyAuxVars(true) {}; ~FznSpace(void) {} /// get the index of the Boolean variable in bv; return -1 if not exists int getBoolAliasIndex(Gecode::BoolVar bvar) { for(unsigned int i=0; i * Andrea Rendl * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_GECODE_CONSTRAINTS_HH__ #define __MINIZINC_GECODE_CONSTRAINTS_HH__ #include #include #include #include namespace MiniZinc { namespace GecodeConstraints { #define PosterImpl(X) void X(SolverInstanceBase& s, const Call* ce) PosterImpl(p_distinct); PosterImpl(p_distinctOffset); PosterImpl(p_all_equal); void p_int_CMP(GecodeSolverInstance& s, Gecode::IntRelType irt, const Call* ce); PosterImpl(p_int_eq); PosterImpl(p_int_ne); PosterImpl(p_int_ge); PosterImpl(p_int_gt); PosterImpl(p_int_le); PosterImpl(p_int_lt); void p_int_CMP_reif(GecodeSolverInstance& s, Gecode::IntRelType irt, Gecode::ReifyMode rm, const Call* call); ///* Comparisons */ PosterImpl(p_int_eq_reif); PosterImpl(p_int_ne_reif); PosterImpl(p_int_ge_reif); PosterImpl(p_int_gt_reif); PosterImpl(p_int_le_reif); PosterImpl(p_int_lt_reif); PosterImpl(p_int_eq_imp); PosterImpl(p_int_ne_imp); PosterImpl(p_int_ge_imp); PosterImpl(p_int_gt_imp); PosterImpl(p_int_le_imp); PosterImpl(p_int_lt_imp); void p_int_lin_CMP(GecodeSolverInstance& s, Gecode::IntRelType irt, const Call* call) ; void p_int_lin_CMP_reif(GecodeSolverInstance& s, Gecode::IntRelType irt, Gecode::ReifyMode rm, const Call* call); PosterImpl(p_int_lin_eq); PosterImpl(p_int_lin_eq_reif); PosterImpl(p_int_lin_eq_imp); PosterImpl(p_int_lin_ne); PosterImpl(p_int_lin_ne_reif); PosterImpl(p_int_lin_ne_imp); PosterImpl(p_int_lin_le) ; PosterImpl(p_int_lin_le_reif); PosterImpl(p_int_lin_le_imp); PosterImpl(p_int_lin_lt); PosterImpl(p_int_lin_lt_reif); PosterImpl(p_int_lin_lt_imp); PosterImpl(p_int_lin_ge); PosterImpl(p_int_lin_ge_reif); PosterImpl(p_int_lin_ge_imp); PosterImpl(p_int_lin_gt); PosterImpl(p_int_lin_gt_reif); PosterImpl(p_int_lin_gt_imp); void p_bool_lin_CMP(GecodeSolverInstance& s, Gecode::IntRelType irt, const Call* call); void p_bool_lin_CMP_reif(GecodeSolverInstance& s, Gecode::IntRelType irt, Gecode::ReifyMode rm, const Call* call); PosterImpl(p_bool_lin_eq); PosterImpl(p_bool_lin_eq_reif); PosterImpl(p_bool_lin_eq_imp) ; PosterImpl(p_bool_lin_ne); PosterImpl(p_bool_lin_ne_reif) ; PosterImpl(p_bool_lin_ne_imp) ; PosterImpl(p_bool_lin_le); PosterImpl(p_bool_lin_le_reif) ; PosterImpl(p_bool_lin_le_imp) ; PosterImpl(p_bool_lin_lt) ; PosterImpl(p_bool_lin_lt_reif); PosterImpl(p_bool_lin_lt_imp) ; PosterImpl(p_bool_lin_ge); PosterImpl(p_bool_lin_ge_reif) ; PosterImpl(p_bool_lin_ge_imp) ; PosterImpl(p_bool_lin_gt) ; PosterImpl(p_bool_lin_gt_reif) ; PosterImpl(p_bool_lin_gt_imp) ; ///* arithmetic constraints */ PosterImpl(p_int_plus); PosterImpl(p_int_minus); PosterImpl(p_int_times); PosterImpl(p_int_div); PosterImpl(p_int_mod); PosterImpl(p_int_min); PosterImpl(p_int_max); PosterImpl(p_int_negate) ; ///* Boolean constraints */ void p_bool_CMP(GecodeSolverInstance& s, Gecode::IntRelType irt, const Call* call); void p_bool_CMP_reif(GecodeSolverInstance& s, Gecode::IntRelType irt, Gecode::ReifyMode rm, const Call* call); PosterImpl(p_bool_eq); PosterImpl(p_bool_eq_reif) ; PosterImpl(p_bool_eq_imp); PosterImpl(p_bool_ne); PosterImpl(p_bool_ne_reif); PosterImpl(p_bool_ne_imp); PosterImpl(p_bool_ge); PosterImpl(p_bool_ge_reif); PosterImpl(p_bool_ge_imp); PosterImpl(p_bool_le); PosterImpl(p_bool_le_reif); PosterImpl(p_bool_le_imp); PosterImpl(p_bool_gt); PosterImpl(p_bool_gt_reif); PosterImpl(p_bool_gt_imp); PosterImpl(p_bool_lt); PosterImpl(p_bool_lt_reif); PosterImpl(p_bool_lt_imp); PosterImpl(p_bool_or) ; PosterImpl(p_bool_or_imp); PosterImpl(p_bool_and); PosterImpl(p_bool_and_imp); PosterImpl(p_array_bool_and); PosterImpl(p_array_bool_and_imp); PosterImpl(p_array_bool_or); PosterImpl(p_array_bool_or_imp); PosterImpl(p_array_bool_xor); PosterImpl(p_array_bool_xor_imp); PosterImpl(p_array_bool_clause); PosterImpl(p_array_bool_clause_reif); PosterImpl(p_array_bool_clause_imp); PosterImpl(p_bool_xor); PosterImpl(p_bool_xor_imp); PosterImpl(p_bool_l_imp); PosterImpl(p_bool_r_imp); PosterImpl(p_bool_not); ///* element constraints */ PosterImpl(p_array_int_element); PosterImpl(p_array_bool_element); ///* coercion constraints */ PosterImpl(p_bool2int); PosterImpl(p_int_in); PosterImpl(p_int_in_reif); PosterImpl(p_int_in_imp); ///* constraints from the standard library */ PosterImpl(p_abs); PosterImpl(p_array_int_lt); PosterImpl(p_array_int_lq); PosterImpl(p_array_bool_lt); PosterImpl(p_array_bool_lq); PosterImpl(p_count); PosterImpl(p_count_reif); PosterImpl(p_count_imp); void count_rel(Gecode::IntRelType irt, SolverInstanceBase& s, const Call* call); PosterImpl(p_at_most); PosterImpl(p_at_least); PosterImpl(p_bin_packing_load); PosterImpl(p_global_cardinality); PosterImpl(p_global_cardinality_closed); PosterImpl(p_global_cardinality_low_up); PosterImpl(p_global_cardinality_low_up_closed); PosterImpl(p_minimum); PosterImpl(p_maximum); PosterImpl(p_minimum_arg); PosterImpl(p_maximum_arg); PosterImpl(p_regular); PosterImpl(p_sort); PosterImpl(p_inverse_offsets); PosterImpl(p_increasing_int); PosterImpl(p_increasing_bool); PosterImpl(p_decreasing_int); PosterImpl(p_decreasing_bool); PosterImpl(p_table_int); PosterImpl(p_table_bool); PosterImpl(p_cumulatives); PosterImpl(p_among_seq_int); PosterImpl(p_among_seq_bool); PosterImpl(p_schedule_unary); PosterImpl(p_schedule_unary_optional); PosterImpl(p_cumulative_opt); PosterImpl(p_circuit); PosterImpl(p_circuit_cost_array); PosterImpl(p_circuit_cost); PosterImpl(p_nooverlap); PosterImpl(p_precede); PosterImpl(p_nvalue); PosterImpl(p_among); PosterImpl(p_member_int); PosterImpl(p_member_int_reif); PosterImpl(p_member_bool); PosterImpl(p_member_bool_reif); #ifdef GECODE_HAS_FLOAT_VARS PosterImpl(p_int2float); void p_float_lin_cmp(GecodeSolverInstance& s, Gecode::FloatRelType frt, const Call* ce); void p_float_lin_cmp_reif(GecodeSolverInstance& s, Gecode::FloatRelType frt, const Call* ce); PosterImpl(p_float_lin_eq); PosterImpl(p_float_lin_eq_reif); PosterImpl(p_float_lin_le); PosterImpl(p_float_lin_le_reif); PosterImpl(p_float_times); PosterImpl(p_float_div); PosterImpl(p_float_plus) ; PosterImpl(p_float_sqrt); PosterImpl(p_float_abs); PosterImpl(p_float_eq); PosterImpl(p_float_eq_reif); PosterImpl(p_float_le); PosterImpl(p_float_le_reif); PosterImpl(p_float_max); PosterImpl(p_float_min); PosterImpl(p_float_lt); PosterImpl(p_float_lt_reif); PosterImpl(p_float_ne); #ifdef GECODE_HAS_MPFR PosterImpl(p_float_acos); PosterImpl(p_float_asin); PosterImpl(p_float_atan); PosterImpl(p_float_cos); PosterImpl(p_float_exp); PosterImpl(p_float_sin); PosterImpl(p_float_tan); PosterImpl(p_float_ln); PosterImpl(p_float_log10); PosterImpl(p_float_log2); #endif #endif #ifdef GECODE_HAS_SET_VARS PosterImpl(p_set_eq); PosterImpl(p_set_le); PosterImpl(p_set_lt); PosterImpl(p_set_eq); PosterImpl(p_set_ne); PosterImpl(p_set_union); PosterImpl(p_array_set_element); PosterImpl(p_array_set_element); PosterImpl(p_set_intersect); PosterImpl(p_set_diff); PosterImpl(p_set_symdiff); PosterImpl(p_set_subset); PosterImpl(p_set_superset); PosterImpl(p_set_card); PosterImpl(p_set_in); PosterImpl(p_set_eq_reif); PosterImpl(p_set_le_reif); PosterImpl(p_set_lt_reif); PosterImpl(p_set_eq_reif); PosterImpl(p_set_ne_reif); PosterImpl(p_set_subset_reif); PosterImpl(p_set_superset_reif); PosterImpl(p_set_in_reif); PosterImpl(p_set_in_imp); PosterImpl(p_set_disjoint); PosterImpl(p_link_set_to_booleans); PosterImpl(p_array_set_union); PosterImpl(p_array_set_partition); PosterImpl(p_set_convex); PosterImpl(p_array_set_seq); PosterImpl(p_array_set_seq_union); PosterImpl(p_array_set_element_union); PosterImpl(p_array_set_element_intersect); PosterImpl(p_array_set_element_intersect_in); PosterImpl(p_array_set_element_partition); PosterImpl(p_int_set_channel); PosterImpl(p_range); PosterImpl(p_weights); PosterImpl(p_inverse_set); PosterImpl(p_precede_set); #endif } } #endif libminizinc-2.4.2/include/minizinc/solvers/gecode_solverfactory.hh000066400000000000000000000010661360574160400255300ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_GECODE_SOLVERFACTORY_HH__ #define __MINIZINC_GECODE_SOLVERFACTORY_HH__ namespace MiniZinc { class Gecode_SolverFactoryInitialiser { public: Gecode_SolverFactoryInitialiser(void); }; } #endif libminizinc-2.4.2/include/minizinc/solvers/gecode_solverinstance.hh000066400000000000000000000335701360574160400256720ustar00rootroot00000000000000/* * Main authors: * Kevin Leo * Andrea Rendl * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_GECODE_SOLVER_INSTANCE_HH__ #define __MINIZINC_GECODE_SOLVER_INSTANCE_HH__ #include #include #include #include #ifdef GECODE_HAS_SET_VARS #include #endif #ifdef GECODE_HAS_FLOAT_VARS #include #endif #include #include #include #if GECODE_VERSION_NUMBER < 600000 #error Gecode versions before 6.0 are not supported #endif #define MZ_IntConLevel Gecode::IntPropLevel #define MZ_ICL_VAL Gecode::IPL_VAL #define MZ_ICL_DOM Gecode::IPL_DOM #define MZ_ICL_BND Gecode::IPL_BND #define MZ_ICL_DEF Gecode::IPL_DEF #define MZ_EPK_DEF Gecode::IPL_DEF namespace MiniZinc { /* class GecodeVariable { public: enum vartype {BOOL_TYPE,FLOAT_TYPE,INT_TYPE,SET_TYPE}; protected: Gecode::VarImpBase* _var; vartype _t; /// the index in FznSpace::bv of the boolean variable that corresponds to the int var; if not exists then -1 int _boolAliasIndex; public: GecodeVariable(Gecode::IntVar& x) : _var(x.varimp()), _t(INT_TYPE), _boolAliasIndex(-1) {} GecodeVariable(Gecode::BoolVar& x) : _var(x.varimp()), _t(BOOL_TYPE), _boolAliasIndex(-1) {} GecodeVariable(Gecode::FloatVar& x) : _var(x.varimp()), _t(FLOAT_TYPE), _boolAliasIndex(-1) {} GecodeVariable(Gecode::SetVar& x) : _var(x.varimp()), _t(SET_TYPE), _boolAliasIndex(-1) {} Gecode::IntVar intVar(void) { assert(_t == INT_TYPE); Gecode::Int::IntView iv(static_cast(_var)); return Gecode::IntVar(iv); } Gecode::BoolVar boolVar(void) { assert(_t == BOOL_TYPE); Gecode::Int::BoolView bv(static_cast(_var)); return Gecode::BoolVar(bv); } Gecode::FloatVar floatVar(void) { assert(_t == FLOAT_TYPE); Gecode::Float::FloatView fv(static_cast(_var)); return Gecode::FloatVar(fv); } Gecode::SetVar setVar(void) { assert(_t == FLOAT_TYPE); Gecode::Set::SetView sv(static_cast(_var)); return Gecode::SetVar(sv); } bool isint(void) const { return _t == INT_TYPE; } bool isbool(void) const { return _t == BOOL_TYPE; } bool isfloat(void) const { return _t == FLOAT_TYPE; } bool isset(void) const { return _t == SET_TYPE; } bool hasBoolAlias(void) { return _boolAliasIndex >= 0; } /// set the index in FznSpace::bv of the Boolean variable that corresponds to the int variable void setBoolAliasIndex(int index) { assert(_t == INT_TYPE); assert(index >= 0); _boolAliasIndex = index; } int boolAliasIndex(void) { return _boolAliasIndex; } vartype t(void) const { return _t; } }; */ class GecodeVariable { public: enum vartype {BOOL_TYPE,FLOAT_TYPE,INT_TYPE,SET_TYPE}; protected: /// variable type vartype _t; /// the index in the iv/bv/fv/sv array in the space, depending the type _t unsigned int _index; /// the index in FznSpace::bv of the boolean variable that corresponds to the int var; if not exists then -1 int _boolAliasIndex; public: GecodeVariable(vartype t, unsigned int index) : _t(t), _index(index), _boolAliasIndex(-1) {} bool isint(void) const { return _t == INT_TYPE; } bool isbool(void) const { return _t == BOOL_TYPE; } bool isfloat(void) const { return _t == FLOAT_TYPE; } bool isset(void) const { return _t == SET_TYPE; } bool hasBoolAlias(void) { return _boolAliasIndex >= 0; } /// set the index in FznSpace::bv of the Boolean variable that corresponds to the int variable void setBoolAliasIndex(int index) { assert(_t == INT_TYPE); assert(index >= 0); _boolAliasIndex = index; } int boolAliasIndex(void) { return _boolAliasIndex; } int index(void) { return _index; } Gecode::IntVar& intVar(MiniZinc::FznSpace* space) { assert(_t == INT_TYPE); assert(_index < space->iv.size()); return space->iv[_index]; } Gecode::BoolVar& boolVar(MiniZinc::FznSpace* space) { assert(_t == BOOL_TYPE); assert(_index < space->bv.size()); return space->bv[_index]; } #ifdef GECODE_HAS_FLOAT_VARS Gecode::FloatVar& floatVar(MiniZinc::FznSpace* space) { assert(_t == FLOAT_TYPE); assert(_index < space->fv.size()); return space->fv[_index]; } #endif #ifdef GECODE_HAS_SET_VARS Gecode::SetVar& setVar(MiniZinc::FznSpace* space) { assert(_t == SET_TYPE); assert(_index < space->sv.size()); return space->sv[_index]; } #endif }; class GecodeSolver { public: typedef GecodeVariable Variable; typedef MiniZinc::Statistics Statistics; }; class GecodeEngine; class GecodeOptions : public SolverInstanceBase::Options { public: bool allow_unbounded_vars = false; bool only_range_domains = false; bool sac = false; bool shave = false; bool verbose = false; int pre_passes = 0; bool statistics = false; bool all_solutions = false; int n_solutions = -1; int nodes = 0; int fails = 0; int time = 0; int seed = 1; double decay = 0.5; }; class GecodeSolverInstance : public SolverInstanceImpl { private: bool _print_stats; bool _only_range_domains; bool _run_sac; bool _run_shave; unsigned int _pre_passes; bool _all_solutions; int _n_max_solutions; int _n_found_solutions; bool _allow_unbounded_vars; Model* _flat; public: /// the Gecode space that will be/has been solved FznSpace* _current_space; /// the solution (or NULL if does not exist or not yet computed) FznSpace* _solution; /// the variable declarations with output annotations std::vector _varsWithOutput; /// declaration map for processing and printing output //typedef std::pair DE; //ASTStringMap::t _declmap; /// TODO: we can probably get rid of this std::unordered_map* > arrayMap; /// The solver engine GecodeEngine* engine; Gecode::Search::Options engine_options; GecodeSolverInstance(Env& env, std::ostream& log, SolverInstanceBase::Options* opt); virtual ~GecodeSolverInstance(void); virtual Status next(void); virtual void processFlatZinc(void); virtual Status solve(void); virtual void resetSolver(void); // Presolve the currently loaded model, updating variables with the same // names in the given Model* m. bool presolve(Model* m = NULL); bool sac(bool toFixedPoint, bool shaving); void print_stats(); void processSolution(bool last_sol = false); virtual Expression* getSolutionValue(Id* id); Gecode::Space* getGecodeModel(void); // helpers for getting correct int bounds bool valueWithinBounds(double b); // helper functions for processing flatzinc constraints /// Convert \a arg (array of integers) to IntArgs Gecode::IntArgs arg2intargs(Expression* arg, int offset = 0); /// Convert \a arg (array of Booleans) to IntArgs Gecode::IntArgs arg2boolargs(Expression* arg, int offset = 0); /// Convert \a n to IntSet Gecode::IntSet arg2intset(EnvI& envi, Expression* sl); /// Convert \a n to IntSetArgs Gecode::IntSetArgs arg2intsetargs(EnvI& envi, Expression* arg, int offset = 0); /// Convert \a arg to IntVarArgs Gecode::IntVarArgs arg2intvarargs(Expression* arg, int offset = 0); /// Convert \a arg to BoolVarArgs Gecode::BoolVarArgs arg2boolvarargs(Expression* a, int offset = 0, int siv=-1); /// Convert \a n to BoolVar Gecode::BoolVar arg2boolvar(Expression* e); /// Convert \a n to IntVar Gecode::IntVar arg2intvar(Expression* e); /// Convert \a n to SetVar Gecode::SetVar arg2setvar(Expression* e); /// Convert \a arg to SetVarArgs Gecode::SetVarArgs arg2setvarargs(Expression* arg, int offset = 0, int doffset = 0, const Gecode::IntSet& od=Gecode::IntSet::empty); /// convert \a arg to an ArrayLit (throws InternalError if not possible) ArrayLit* arg2arraylit(Expression* arg); /// Check if \a b is array of Booleans (or has a single integer) bool isBoolArray(ArrayLit* a, int& singleInt); #ifdef GECODE_HAS_FLOAT_VARS /// Convert \a n to FloatValArgs Gecode::FloatValArgs arg2floatargs(Expression* arg, int offset = 0); /// Convert \a n to FloatVar Gecode::FloatVar arg2floatvar(Expression* n); /// Convert \a n to FloatVarArgs Gecode::FloatVarArgs arg2floatvarargs(Expression* arg, int offset = 0); #endif /// Convert \a ann to IntConLevel MZ_IntConLevel ann2icl(const Annotation& ann); /// convert the annotation \a s int variable selection to the respective Gecode var selection Gecode::TieBreak ann2ivarsel(std::string s, Gecode::Rnd& rnd, double decay); /// convert the annotation \a s int value selection to the respective Gecode val selection Gecode::IntValBranch ann2ivalsel(std::string s, std::string& r0, std::string& r1, Gecode::Rnd& rnd); /// convert assign value selection Gecode::IntAssign ann2asnivalsel(std::string s, Gecode::Rnd& rnd); Gecode::TieBreak ann2bvarsel(std::string s, Gecode::Rnd& rnd, double decay); /// convert the annotation \a s int value selection to the respectbve Gecode val selection Gecode::BoolValBranch ann2bvalsel(std::string s, std::string& r0, std::string& r1, Gecode::Rnd& rnd); /// convert assign value selection Gecode::BoolAssign ann2asnbvalsel(std::string s, Gecode::Rnd& rnd); #ifdef GECODE_HAS_SET_VARS Gecode::SetVarBranch ann2svarsel(std::string s, Gecode::Rnd& rnd, double decay); Gecode::SetValBranch ann2svalsel(std::string s, std::string r0, std::string r1, Gecode::Rnd& rnd); #endif #ifdef GECODE_HAS_FLOAT_VARS Gecode::TieBreak ann2fvarsel(std::string s, Gecode::Rnd& rnd, double decay); Gecode::FloatValBranch ann2fvalsel(std::string s, std::string r0, std::string r1); #endif /// Returns the VarDecl of \a expr and throws an InternalError if not possible VarDecl* getVarDecl(Expression* expr); /// Returns the VarDecl of \a aa VarDecl* resolveArrayAccess(ArrayAccess* aa); /// Returns the VarDecl of \a array at index \a index VarDecl* resolveArrayAccess(VarDecl* array, int index); /// Returns the GecodeVariable representing the Id, VarDecl or ArrayAccess GecodeSolver::Variable resolveVar(Expression* e); /// Inserts variable gv into _variableMap with key id void insertVar(Id* id, GecodeVariable gv); protected: void registerConstraints(void); void registerConstraint(std::string name, poster p); /// creates the gecode branchers // TODO: what is decay, ignoreUnknown -> do we need all the args? void createBranchers(Annotation& ann, Expression* additionalAnn, int seed, double decay, bool ignoreUnknown, std::ostream& err); void prepareEngine(void); void setSearchStrategyFromAnnotation(std::vector flatAnn, std::vector& iv_searched, std::vector& bv_searched, #ifdef GECODE_HAS_SET_VARS std::vector& sv_searched, #endif #ifdef GECODE_HAS_FLOAT_VARS std::vector& fv_searched, #endif Gecode::TieBreak& def_int_varsel, Gecode::IntValBranch& def_int_valsel, Gecode::TieBreak& def_bool_varsel, Gecode::BoolValBranch& def_bool_valsel, #ifdef GECODE_HAS_SET_VARS Gecode::SetVarBranch& def_set_varsel, Gecode::SetValBranch& def_set_valsel, #endif #ifdef GECODE_HAS_FLOAT_VARS Gecode::TieBreak& def_float_varsel, Gecode::FloatValBranch& def_float_valsel, #endif Gecode::Rnd& rnd, double decay, bool ignoreUnknown, std::ostream& err ); }; class Gecode_SolverFactory: public SolverFactory { public: Gecode_SolverFactory(void); SolverInstanceBase::Options* createOptions(void); SolverInstanceBase* doCreateSI(Env& env, std::ostream& log, SolverInstanceBase::Options* opt); std::string getDescription(SolverInstanceBase::Options* opt=NULL); std::string getVersion(SolverInstanceBase::Options* opt=NULL); std::string getId( ) { return "org.minizinc.gecode_presolver"; } virtual bool processOption(SolverInstanceBase::Options* opt, int& i, std::vector& argv); void printHelp(std::ostream& os); }; } #endif libminizinc-2.4.2/include/minizinc/solvers/mzn_solverfactory.hh000066400000000000000000000010531360574160400251020ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_MZN_SOLVERFACTORY_HH__ #define __MINIZINC_MZN_SOLVERFACTORY_HH__ namespace MiniZinc { class MZN_SolverFactoryInitialiser { public: MZN_SolverFactoryInitialiser(void); }; } #endif libminizinc-2.4.2/include/minizinc/solvers/mzn_solverinstance.hh000066400000000000000000000037071360574160400252470ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_MZN_SOLVER_INSTANCE_HH__ #define __MINIZINC_MZN_SOLVER_INSTANCE_HH__ #include namespace MiniZinc { class MZNSolverOptions : public SolverInstanceBase::Options { public: std::string mzn_solver; std::vector mzn_flags; int numSols = 1; bool allSols = false; std::string parallel; int mzn_time_limit_ms = 0; int solver_time_limit_ms = 0; bool mzn_sigint = false; bool supports_t = false; std::vector mzn_solver_flags; }; class MZNSolverInstance : public SolverInstanceBase { private: std::string _mzn_solver; public: MZNSolverInstance(Env& env, std::ostream& log, SolverInstanceBase::Options* opt); ~MZNSolverInstance(void); Status next(void) {return SolverInstance::ERROR;} Status solve(void); void processFlatZinc(void); void resetSolver(void); }; class MZN_SolverFactory: public SolverFactory { protected: virtual SolverInstanceBase* doCreateSI(Env& env, std::ostream& log, SolverInstanceBase::Options* opt); public: MZN_SolverFactory(void); virtual SolverInstanceBase::Options* createOptions(void); virtual std::string getDescription(SolverInstanceBase::Options* opt=NULL); virtual std::string getVersion(SolverInstanceBase::Options* opt=NULL); virtual std::string getId(void); virtual bool processOption(SolverInstanceBase::Options* opt, int& i, std::vector& argv); virtual void printHelp(std::ostream& os); void setAcceptedFlags(SolverInstanceBase::Options* opt, const std::vector& flags); }; } #endif libminizinc-2.4.2/include/minizinc/solvers/nl/000077500000000000000000000000001360574160400214055ustar00rootroot00000000000000libminizinc-2.4.2/include/minizinc/solvers/nl/nl_components.hh000066400000000000000000000424311360574160400246100ustar00rootroot00000000000000#ifndef __MINIZINC_NL_COMPONENTS_HH__ #define __MINIZINC_NL_COMPONENTS_HH__ //#include #include #include #include #include #include using namespace std; /* A NL File is composed of a header and several segments. Adding items in the nl file is done through adding segment (or adding item in a segment). As for the header, segment are printable. Segment are identified by a prefix, which should be one of (taken from table 13 in 'writing nl files'): F imported function description S suffix values V defined variable definition (must precede V,C,L,O segments where used) (yes, I know, "V must preceed V"...) C algebraic constraint body L logical constraint expression O objective function d dual initial guess x primal initial guess r bounds on algebraic constraint bodies (“ranges”), can only appears once b bounds on variable, can only appears once k Jacobian column counts (must precede all J segments) J Jacobian sparsity, linear terms G Gradient sparsity, linear terms */ namespace MiniZinc { // --- --- --- Tooling /** Exception when translating * Code mostly taken from https://www.softwariness.com/articles/assertions-in-cpp/ */ class NLException: public exception { public: // --- --- --- Fields const char* expression; const char* file; int line; string message; string report; /** Exception constructor. Use with the macro assert/should_not_happen. * If not, WARNING: stream must be a std::ostringstream& * We only use a ostreamé so we can use the standard "<<" operator, which is returning a ostream& */ NLException(const char* expression, const char* file, int line, ostream& stream): expression(expression), file(file), line(line) { message = static_cast(stream).str(); std::ostringstream outputStream; if(expression==NULL){ outputStream << "Something should not have happen in file '" << file << "' line " << line << ". Message:" << endl; if (!message.empty()){ outputStream << message << endl; } else { outputStream << "No message provided..." << endl;} } else { string expressionString = expression; if (expressionString == "false" || expressionString == "0" || expressionString == "FALSE"){ outputStream << "Unreachable code assertion"; } else { outputStream << "Assertion '" << expression << "'"; } outputStream << " failed in file '" << file << "' line " << line << endl; } outputStream << "Note: the NL component is still in development!" << endl; report = outputStream.str(); } /** Exception interface */ virtual const char* what() const noexcept { return report.c_str(); } ~NLException() noexcept = default; }; #ifdef assert #undef assert #endif /** Should not happen macro */ #define should_not_happen(MESSAGE) do{ ostringstream oss; oss << MESSAGE; throw NLException(NULL, __FILE__, __LINE__, oss); }while(false) /* CMake febug build flag: double negation... because... ? */ #ifndef NDEBUG #define DEBUG_MSG(STR) do { std::cerr << "%[NL DEBUG] " << STR << endl;} while( false ) #define assert(EXPRESSION) do{ if(!(EXPRESSION)) { ostringstream oss; throw NLException(#EXPRESSION, __FILE__, __LINE__, oss); } }while(false) #else #define DEBUG_MSG(STR) do { } while ( false ) #define assert(EXPRESSION) do { } while ( false ) #endif // --- --- --- Components // Declaration class NLFile; /** A Bound. * A bound can represent various constraint on a variable or a constraint. * Because it apply to both variables and constraints, we keep it general enough. * Note that the targeted variable or constraint is implicitely represented by its position in the final NL File. * As a result, this information does not appear here. * Bounds are used in the 'b' and 'r' segments. # Text # Starting the segment # Variable # Tag in enum NLS_Bounditem::Bound 0 1.1 3.4 # 1.1 =< V =< 3.4 First variable LB_UB 1 2.5 # V =< 2.5 Second variable UB 2 7 # 7 =< V etc... LB 3 # no constraint NONE 4 9.4 # V = 9.4 EQ * Notes: - bound values are stored as 'double', even for integer variables. * - we do not make that class Printable as it is better "printed" with a name for the targeted variable/constraint */ class NLBound{ public: /** Bound kind. Declaration matches specification above. */ enum Bound { LB_UB = 0, UB = 1, LB = 2, NONE = 3, EQ = 4 }; /** *** *** *** Fields *** *** *** **/ Bound tag=NONE; double lb=0; double ub=0; /** *** *** *** Constructors & helpers *** *** *** **/ NLBound() = default; NLBound(Bound tag, double lb, double ub); static NLBound make_bounded(double lb, double ub); static NLBound make_ub_bounded(double ub); static NLBound make_lb_bounded(double lb); static NLBound make_nobound(); static NLBound make_equal(double val); /** *** *** *** Update the lower or upper bound *** *** *** **/ // Note: this method are "additive only": we cannot use them to remove a a bound. void update_lb(double new_lb); void update_ub(double new_ub); void update_eq(double new_eq); /** *** *** *** Printing Methods *** *** *** **/ /** Print the bound with a comment containing the name of the variable/constraint. */ ostream& print_on( ostream& o, string vname) const; /** Printing with 'body' as the name of the variable/constraint. */ ostream& print_on( ostream& o) const; }; /** A Declared variable. * A variable is identified by its name, which is supposed to be unique in the MZN representation. * In an NL file, variables are identified by their index. However, those index are dependent on the variable ordering, * which can only be known once all variables are known. Hence, the computation of the index can only be achieved at a later stage. * A variable is always associated to a bound, even if none are specified (See LNBound above)/ */ class NLVar { public: /** Variable name. */ string name; /** Is the variable an integer variable? Else is a floating point variable. */ bool is_integer = false; /** Is this variable flagged to be reported? */ bool to_report = false; /** Is the variable appearing in a nonlinear constraint (including logical constraint, L segment). */ bool is_in_nl_constraint = false; /** Is the variable appearing non linearly in the objective? */ bool is_in_nl_objective = false; /** Number of occurrences in Jacobian. */ long jacobian_count = 0; /** The bound over this variable. * Used when producing the unique 'b' segment of the NL file. */ NLBound bound; /* *** *** *** Constructors *** *** *** */ NLVar() = default; /** Constructor with declare time information */ NLVar(const string &name, bool is_integer, bool to_report, NLBound bound): name(name), is_integer(is_integer), to_report(to_report), bound(bound){} /** Copy constructor, with update on bound */ NLVar copy_with_bound(NLBound bound) const; }; /** A NLArray: * We do not use "real" array. * This type only serves when sending the result back to minizinc */ class NLArray{ public: /** Array item; if the string is empty, use the value. */ class Item { public: string variable; double value; }; /** Array name */ string name; /** Dimensions part, e.g. array2d( '0..4', '0..5' [ .... ]) */ vector dimensions; /** Related variables */ vector items; /** Is this an array or integers or floats? */ bool is_integer = false; }; /** A token from an 'expression graph'. * An expression graph is express in Polish Prefix Notation: operator followed by operand. * A token represent an operator or an operand. * See the definition of the various enum. */ class NLToken { public: /** Kind of token. */ enum Kind{ NUMERIC, // "n42.42" a numeric constant, double VARIABLE, // "v4" reference to a decision variable 0<= i < nb_vars (see header) or a defined variable for i>=nb_vars STRING, // "h11:some string" Probably unused in our case. FUNCALL, // "f0 3" Call a defined function (index 0, 3 args). Probably unused in our case. OP, // "o5" An operation defined by its operation code MOP // "o7\n3" Operator with multiple operand. The number of operands (3) is on the next line ("\n")? }; /** Opcode for operator with a fixed number of operands. */ enum OpCode{ OPPLUS = 0, OPMINUS = 1, OPMULT = 2, OPDIV = 3, OPREM = 4, OPPOW = 5, OPLESS = 6, FLOOR = 13, CEIL = 14, ABS = 15, OPUMINUS = 16, OPOR = 20, OPAND = 21, LT = 22, LE = 23, EQ = 24, GE = 28, GT = 29, NE = 30, OPNOT = 34, OPIFnl = 35, OP_tanh = 37, OP_tan = 38, OP_sqrt = 39, OP_sinh = 40, OP_sin = 41, OP_log10 = 42, OP_log = 43, OP_exp = 44, OP_cosh = 45, OP_cos = 46, OP_atanh = 47, OP_atan2 = 48, OP_atan = 49, OP_asinh = 50, OP_asin = 51, OP_acosh = 52, OP_acos = 53, OPintDIV = 55, OPprecision = 56, OPround = 57, OPtrunc = 58, OPATLEAST = 62, OPATMOST = 63, OPPLTERM = 64, OPIFSYM = 65, OPEXACTLY = 66, OPNOTATLEAST = 67, OPNOTATMOST = 68, OPNOTEXACTLY = 69, OPIMPELSE = 72, OP_IFF = 73, OPSOMESAME = 75, OP1POW = 76, OP2POW = 77, OPCPOW = 78, OPFUNCALL = 79, OPNUM = 80, OPHOL = 81, OPVARVAL = 82, N_OPS = 83, }; /** Opcodes for operand taking multiple arguments. */ enum MOpCode{ MINLIST = 11, MAXLIST = 12, OPSUMLIST = 54, OPCOUNT = 59, OPNUMBEROF = 60, OPNUMBEROFs = 61, ANDLIST = 70, ORLIST = 71, OPALLDIFF = 74, }; /** Obtain the name of an operator from its opcode. */ static const char* get_name(OpCode oc); /** Obtain the name of an operator (with multiple operands) from its opcode. */ static const char* get_name(MOpCode moc); /* *** *** *** Fields *** *** *** */ Kind kind; double numeric_value; // if kind==NUMERIC int nb_args; // if kind==FUNCALL or kind==MOP string str; // if kind==STRING or kind=VARIABLE (variable name) or kind=FUNCALL (function name) OpCode oc; // if kind==OP MOpCode moc; // if kind==MOP /* *** *** *** Constructor and helpers *** *** *** */ NLToken()=default; static NLToken n(double value); static NLToken v(string vname); static NLToken o(OpCode opc); static NLToken mo(MOpCode mopc, int nb); /* *** *** *** Query *** *** *** */ bool is_variable() const; bool is_constant() const; /* *** *** *** Printable *** *** *** */ ostream& print_on( ostream& o, const NLFile& nl_file) const; }; /** A algebraic constraint. * Contains both a linear and a non linear part. * We do not handle network constraints. */ class NLAlgCons { public: /** Constraint name, also acts as identifier. */ string name; /** Bound on the algebraic constraint. * Used when producing the unique r of the NL file. */ NLBound range; /** Expression graph, used for the non linear part. * Used to produce a new, standalone, C segment. * If the expression graph is empty (linear constraint), produce the expression graph 'n0' */ vector expression_graph = {}; /** Jacobian, used for the linear part. Identify a variable by its name and associate a coefficent. * Used to produce a new, standalone, J segment. */ vector> jacobian = {}; /** Method to build the var_coeff vector. * The NLFile is used to access the variables through their name in order to increase their jacobian count. */ void set_jacobian(const vector& vnames, const vector& coeffs, NLFile* nl_file); /* *** *** *** Helpers *** *** *** */ /** A constraint is considered linear if the expression_graph is empty. */ bool is_linear() const; /* *** *** *** Printable *** *** *** */ ostream& print_on( ostream& o, const NLFile& nl_file) const; }; /** A logical constraint. * Contains only a non linear part. * We do not handle network constraints. * Logical constraint stands on their own and do not need any identifier. * However, for consistency sake, we still keep their name. */ class NLLogicalCons { public: /** Constraint name, also acts as identifier. */ string name; /** Index */ int index=-1; /** Expression graph, used for the non linear part. * Used to produce a new, standalone, L segment. * If the expression graph is empty (linear constraint), produce the expression graph 'n0' */ vector expression_graph = {}; /* *** *** *** Constructor *** *** *** */ NLLogicalCons(int idx):index(idx){} /* *** *** *** Printable *** *** *** */ ostream& print_on( ostream& o, const NLFile& nl_file) const; }; /** The header. */ class NLHeader { public: /* *** *** *** Printable *** *** *** */ ostream& print_on( ostream& o, const NLFile& nl_file) const; }; /** An Objective * In an NL file, we can have several of those. * However, in flatzinc, only one is allowed, so we only have one. * Note that in NL, we do not have a "satisfy" objective, only a minimize or maximize one. * We translate the "satisfy" with "minimize n0". */ class NLObjective { public: enum MinMax{ UNDEF = -2, SATISFY = -1, MINIMIZE = 0, MAXIMIZE = 1, }; /* *** *** *** Fields *** *** *** */ MinMax minmax = UNDEF; vector expression_graph = {}; // If empty, produce a 'n0' when printing /* *** *** *** Gradient *** *** *** */ /** Gradient, used for the linear part. Identify a variable by its name and associate a coefficent. * Used to produce a new, standalone, G segment. */ vector> gradient = {}; /** Method to build the var_coeff vector. */ void set_gradient(const vector& vnames, const vector& coeffs); int gradient_count() const; /* *** *** *** Helpers *** *** *** */ bool is_defined() const; bool is_linear() const; bool is_optimisation() const; /* *** *** *** Constructor *** *** *** */ NLObjective() = default; /* *** *** *** Printable *** *** *** */ ostream& print_on( ostream& o, const NLFile& nl_file ) const; }; } #endif libminizinc-2.4.2/include/minizinc/solvers/nl/nl_file.hh000066400000000000000000000536421360574160400233500ustar00rootroot00000000000000/** * Describe the structure of a NL file. * Main author: Matthieu Herrmann, Monash University, Melbourne, Australia. 2019 **/ #ifndef __MINIZINC_NL_FILE_HH__ #define __MINIZINC_NL_FILE_HH__ #include #include #include #include #include #include #include using namespace std; // This files declare data-structure describing the various components of a nl files. // A nl files is composed of two main parts: a header and a list of segments. // The header contains statistics and meta information about the model. // The segments allow to describe the model, i.e. the variables, the constraints and objectives. // The order of the segments and, when relevant, the order of their content // (e.g. a segment declaring a list of variables) matters. /** NL File. * Good to know: * * We use string as variable unique identifier. * Given a MZN variable declaration (can be obtain from a MZN variable), the 'get_vname' helper produces the string. * * In our case, we only have one 'solve' per file. * * NL file use double everywhere. Hence, even with dealing with integer variable, we store the information with double. * */ namespace MiniZinc { // --- --- --- NL Files class NLFile { public: /* *** *** *** Helpers *** *** *** */ /** Create a string representing the name (and unique identifier) from an identifier. */ static string get_vname(const Id *id); /** Create a string representing the name (and unique identifier) of a variable from a variable declaration. */ static string get_vname(const VarDecl &vd); /** Create a string representing the name (and unique identifier) of a constraint from a specific call expression. */ static string get_cname(const Call& c); /** Extract an array literal from an expression. */ static const ArrayLit& get_arraylit(const Expression* e); /** Create a vector of double from a vector containing Expression being integer literal IntLit. */ static vector from_vec_int(const ArrayLit& v_int); /** Create a vector of double from a vector containing Expression being float literal FloatLit. */ static vector from_vec_fp(const ArrayLit& v_fp); /** Create a vector of variable names from a vector containing Expression being identifier Id. */ static vector from_vec_id(const ArrayLit& v_id); /* *** *** *** Phase 1: collecting data from MZN *** *** *** */ // Variables collection, identified by name // Needs ordering, see phase 2 map variables={}; // Algebraic constraints collection, identified by name // Needs ordering, see phase 2 map constraints={}; // Logical constraints do not need ordering: vector logical_constraints={}; // Objective field. Only one, so we do not need ordering. NLObjective objective = {}; // Output arrays vector output_arrays = {}; /** Add a solve goal in the NL File. In our case, we can only have one and only one solve goal. */ void add_solve(SolveI::SolveType st, const Expression* e); /** Add a variable declaration in the NL File. * This function pre-analyse the declaration VarDecl, then delegate to add_vdecl_integer or add_vdecl_fp. * Analyse a variable declaration 'vd' of type 'ti' with an 'rhs'. * The variable declaration gives us access to the variable name while the type allows us to discriminate between integer, * floating point value and arrays. * Array are ignored (not declared): if we encouter an array in a constraint, we can find the array through the variable (ot it is a litteral). * Notes: - We use -Glinear, so we do not have boolean. * - This will change TODO keep checking comment and code consistency. * * RHS is for arrays: it contains the definition of the array. * * The type also gives us the domain, which can be: * NULL: no restriction over the variable * SetLit: Gives us a lower and upper bound * If a variable is bounded only on one side, then the domain is NULL and the bound is expressed through a constraint. */ void add_vdecl(const VarDecl &vd, const TypeInst &ti, const Expression &rhs); /** Add an integer variable declaration to the NL File. */ void add_vdecl_integer(const string& name, const IntSetVal* isv, bool to_report); /** Add a floating point variable declaration to the NL File. */ void add_vdecl_fp(const string& name, const FloatSetVal* fsv, bool to_report); // --- --- --- Constraints analysis /** Add a constraint to the NL File. * This method is a dispatcher for all the other constraints methods below. */ void analyse_constraint(const Call& c); // --- --- --- Helpers /** Create a token from an expression representing a variable. * ONLY USE FOR CONSTRAINT, NOT OBJECTIVES! (UPDATE VARIABLES FLAG FOR CONSTRAINTS) */ NLToken get_tok_var(const Expression* e); /** Create a token from an expression representing either a variable or an integer numeric value. * ONLY USE FOR CONSTRAINT, NOT OBJECTIVES! */ NLToken get_tok_var_int(const Expression* e); /** Create a token from an expression representing either a variable or a floating point numeric value. * ONLY USE FOR CONSTRAINT, NOT OBJECTIVES! */ NLToken get_tok_var_fp(const Expression* e); /** Update an expression graph (only by appending token) with a linear combination * of coefficients and variables. * ONLY USE FOR CONSTRAINTS, NOT OBJECTIVES! */ void make_SigmaMult(vector& expression_graph, const vector& coeffs, const vector& vars); // --- --- --- Linear Builders // Use an array of literals 'coeffs' := c.arg(0), an array of variables 'vars' := c.arg(1), // and a variable or literal 'value' := c.arg(2). // [coeffs] and value are fixed (no variable allowed). // The call is needed to create the name. However, the extraction of the coefficients and the value // is left to the calling function as this could be use with both integer and floating point // (we only have floating point in NL) /** Create a linear constraint [coeffs] *+ [vars] = value. */ void lincons_eq(const Call& c, const vector& coeffs, const vector& vars, NLToken value); /** Create a linear constraint [coeffs] *+ [vars] <= value. */ void lincons_le(const Call& c, const vector& coeffs, const vector& vars, NLToken value); /** Create a linear logical constraint [coeffs] *+ [vars] PREDICATE value. * Use a generic comparison operator. * Warnings: - Creates a logical constraint * - Only use for conmparisons that cannot be expressed with '=' xor '<='. */ void lincons_predicate(const Call& c, NLToken::OpCode oc, const vector& coeffs, const vector& vars, NLToken value); // --- --- --- Non Linear Builders // For predicates, uses 2 variables or literals: x := c.arg(0), y := c.arg(1) // x PREDICATE y // For unary operations, uses 2 variables or literals: x := c.arg(0), y := c.arg(1) // OPEARTOR x = y // For binary operations, uses 3 variables or literals: x := c.arg(0), y := c.arg(1), and z := c.arg(2). // x OPERATOR y = z /** Create a non linear constraint x = y * Use the jacobian and the bound on constraint to translate into x - y = 0 * Simply update the bound if one is a constant. */ void nlcons_eq(const Call& c, NLToken x, NLToken y); /** Create a non linear constraint x <= y * Use the jacobian and the bound on constraint to translate into x - y <= 0 * Simply update the bound if one is a constant. */ void nlcons_le(const Call& c, NLToken x, NLToken y); /** Create a non linear constraint with a predicate: x PREDICATE y * Use a generic comparison operator. * Warnings: - Creates a logical constraint * - Only use for conmparisons that cannot be expressed with '=' xor '<='. */ void nlcons_predicate(const Call& c, NLToken::OpCode oc, NLToken x, NLToken y); /** Create a non linear constraint with a binary operator: x OPERATOR y = z */ void nlcons_operator_binary(const Call& c, NLToken::OpCode oc, NLToken x, NLToken y, NLToken z); /** Create a non linear constraint with a binary operator: x OPERATOR y = z. * OPERATOR is now a Multiop, with a count of 2 (so the choice of the method to use depends on the LN implementation) */ void nlcons_operator_binary(const Call& c, NLToken::MOpCode moc, NLToken x, NLToken y, NLToken z); /** Create a non linear constraint with an unary operator: OPERATOR x = y */ void nlcons_operator_unary(const Call& c, NLToken::OpCode oc, NLToken x, NLToken y); /** Create a non linear constraint, specialized for log2 unary operator: Log2(x) = y */ void nlcons_operator_unary_log2(const Call& c, NLToken x, NLToken y); // --- --- --- Integer Linear Constraints /** Linar constraint: [coeffs] *+ [vars] = value */ void consint_lin_eq(const Call& c); /** Linar constraint: [coeffs] *+ [vars] =< value */ void consint_lin_le(const Call& c); /** Linar constraint: [coeffs] *+ [vars] != value */ void consint_lin_ne(const Call& c); // --- --- --- Integer Non Linear Predicate Constraints /** Non linear constraint x = y */ void consint_eq(const Call& c); /** Non linear constraint x <= y */ void consint_le(const Call& c); /** Non linear constraint x != y */ void consint_ne(const Call& c); // --- --- --- Integer Non Linear Binary Operator Constraints /** Non linear constraint x + y = z */ void consint_plus(const Call& c); /** Non linear constraint x * y = z */ void consint_times(const Call& c); /** Non linear constraint x / y = z */ void consint_div(const Call& c); /** Non linear constraint x mod y = z */ void consint_mod(const Call& c); /** Non linear constraint x pow y = z */ void int_pow(const Call& c); /** Non linear constraint max(x, y) = z */ void int_max(const Call& c); /** Non linear constraint min(x, y) = z */ void int_min(const Call& c); // --- --- --- Integer Non Linear Unary Operator Constraints void int_abs(const Call& c); // --- --- --- Floating Point Linear Constraints /** Linar constraint: [coeffs] *+ [vars] = value */ void consfp_lin_eq(const Call& c); /** Linar constraint: [coeffs] *+ [vars] = value */ void consfp_lin_le(const Call& c); /** Linar constraint: [coeffs] *+ [vars] != value */ void consfp_lin_ne(const Call& c); /** Linar constraint: [coeffs] *+ [vars] < value */ void consfp_lin_lt(const Call& c); // --- --- --- Floating Point Non Linear Predicate Constraints /** Non linear constraint x = y */ void consfp_eq(const Call& c); /** Non linear constraint x <= y */ void consfp_le(const Call& c); /** Non linear constraint x != y */ void consfp_ne(const Call& c); /** Non linear constraint x < y */ void consfp_lt(const Call& c); // --- --- --- Floating Point Non Linear Binary Operator Constraints /** Non linear constraint x + y = z */ void consfp_plus(const Call& c); /** Non linear constraint x - y = z */ void consfp_minus(const Call& c); /** Non linear constraint x * y = z */ void consfp_times(const Call& c); /** Non linear constraint x / y = z */ void consfp_div(const Call& c); /** Non linear constraint x mod y = z */ void consfp_mod(const Call& c); /** Non linear constraint x pow y = z */ void float_pow(const Call& c); /** Non linear constraint max(x, y) = z */ void float_max(const Call& c); /** Non linear constraint min(x, y) = z */ void float_min(const Call& c); // --- --- --- Floating Point Non Linear Unary Operator Constraints /** Non linear constraint abs x = y */ void float_abs(const Call& c); /** Non linear constraint acos x = y */ void float_acos(const Call& c); /** Non linear constraint acosh x = y */ void float_acosh(const Call& c); /** Non linear constraint asin x = y */ void float_asin(const Call& c); /** Non linear constraint asinh x = y */ void float_asinh(const Call& c); /** Non linear constraint atan x = y */ void float_atan(const Call& c); /** Non linear constraint atanh x = y */ void float_atanh(const Call& c); /** Non linear constraint cos x = y */ void float_cos(const Call& c); /** Non linear constraint cosh x = y */ void float_cosh(const Call& c); /** Non linear constraint exp x = y */ void float_exp(const Call& c); /** Non linear constraint ln x = y */ void float_ln(const Call& c); /** Non linear constraint log10 x = y */ void float_log10(const Call& c); /** Non linear constraint log2 x = y */ void float_log2(const Call& c); /** Non linear constraint sqrt x = y */ void float_sqrt(const Call& c); /** Non linear constraint sin x = y */ void float_sin(const Call& c); /** Non linear constraint sinh x = y */ void float_sinh(const Call& c); /** Non linear constraint tan x = y */ void float_tan(const Call& c); /** Non linear constraint tanh x = y */ void float_tanh(const Call& c); // --- --- --- Other /** Integer x to floating point y. Constraint x = y translated into x - y = 0. */ void int2float(const Call& c); /* *** *** *** Phase 2: processing *** *** *** */ void phase_2(); // Ordering of variables according to "hooking your solver" /* Meaning of the names (total, then by appearance order in the tables below) n_var total number of variables nlvc number of variables appearing nonlinearly in constraints nlvo number of variables appearing nonlinearly in objectives nwv number of linear arcs niv number of "other" integer variables nbv number of binary variables Order of variables (yes, the way things are counted is... "special".) Category Count --- --- --- --- | --- --- --- --- --- nonlinear max(nlvc, nlvo) // See below for order on non linear variables linear arcs nwv // Not implemented other linear n_var − (max {nlvc, nlvo} + niv + nbv + nwv) // Linear Continuous binary nbv // Booleans other integer niv // Linear Integer Order of non linear variables (see 'nonlinear' above) Meaning of the names: nlvb number of variables appearing nonlinearly in both constraints and objectives nlvbi number of integer variables appearing nonlinearly in both constraints and objectives nlvc number of variables appearing nonlinearly in constraints nlvci number of integer variables appearing nonlinearly in constraints **only** nlvo number of variables appearing nonlinearly in objectives nlvoi number of integer variables appearing nonlinearly in objectives **only** Category Count --- --- --- --- --- --- --- --- --- --- --- --- --- | --- --- --- --- --- Continuous in BOTH an objective AND a constraint | nlvb - nlvbi Integer, in BOTH an objective AND a constraint | nlvbi Continuous, in constraints only | nlvc − (nlvb + nlvci) Integer, in constraints only | nlvci Continous, in objectives only | nlvo − (nlvc + nlvoi) Integer, in objectives only | nlvoi */ /** Non Linear Continuous Variables in BOTH an objective and a constraint. */ vector vname_nlcv_both = {}; /** Non Linear Integer Variables in BOTH an objective and a constraint. */ vector vname_nliv_both = {}; /** Non Linear Continuous Variables in CONStraints only. */ vector vname_nlcv_cons = {}; /** Non Linear Integer Variables in CONStraints only. */ vector vname_nliv_cons = {}; /** Non Linear Continuous Variables in OBJectives only. */ vector vname_nlcv_obj = {}; /** Non Linear Integer Variables in OBJectives only. */ vector vname_nliv_obj = {}; /** Linear arcs. (Network not implemented) */ vector vname_larc_all = {}; /** Linear Continuous Variables (ALL of them). */ vector vname_lcv_all = {}; /** Binary Variables (ALL of them). */ vector vname_bv_all = {}; /** Linear Integer Variables (ALL of them). */ vector vname_liv_all = {}; /** Contained all ordered variable names. Mapping variable index -> variable name */ vector vnames={}; /** Mapping variable name -> variable index */ map variable_indexes={}; // --- --- --- Simple tests bool has_integer_vars() const; bool has_continous_vars() const; // --- --- --- Variables counts // When the phase 2 is done, all the following counts should be available. // taken from "hooking your solver" and used in the above explanatios /** Total number of variables. */ int n_var() const; /** Number of variables appearing nonlinearly in constraints. */ int nlvc() const; /** Number of variables appearing nonlinearly in objectives. */ int nlvo() const; /** Number of variables appearing nonlinearly in both constraints and objectives.*/ int nlvb() const; /** Number of integer variables appearing nonlinearly in both constraints and objectives.*/ int nlvbi() const; /** Number of integer variables appearing nonlinearly in constraints **only**.*/ int nlvci() const; /** Number of integer variables appearing nonlinearly in objectives **only**.*/ int nlvoi() const; /** Number of linear arcs .*/ int nwv() const; /** Number of "other" integer variables.*/ int niv() const; /** Number of binary variables.*/ int nbv() const; /** Accumulation of Jacobian counts. */ int jacobian_count() const; int _jacobian_count = 0; // Ordering of constraints according to "hooking your solver" /* Meaning of the names: n_con Total number of constraint nlc Number of nonlinear general constraint, including network constraint nlnc Number of nonlinear network constraint lnc Number of linear network constraint Order of constraints: Category Count --- --- --- --- --- | --- --- --- --- --- Nonlinear general nlc - nlnc Nonlinear network nlnc Linear network lnc Linear general n_con - (nlc + lnc) */ /** Nonlinear general constraints. */ vector cnames_nl_general = {}; /** Nonlinear network constraints. */ vector cnames_nl_network = {}; /** Linear network constraints. */ vector cnames_lin_network = {}; /** Linear general constraints. */ vector cnames_lin_general = {}; /** Contained all ordered algebraic (and network if they were implemented) constraints names. * Mapping constraint index -> constraint name */ vector cnames={}; /** Mapping constraint name -> contraint index */ map constraint_indexes={}; // Count of algebraic constraints: // The header needs to know how many range algebraic constraints and equality algebraic constraints we have. /** Number of range algebraic constraints */ int nb_alg_cons_range = 0; /** equality algebraic constraints */ int nb_alg_cons_eq = 0; /* *** *** *** Constructor *** *** *** */ NLFile() = default; /* *** *** *** Printable *** *** *** */ /** Print the NLFile on a stream. * Note: this is not the 'Printable' interface as we do not pass any nl_file (that would be 'this') as a reference. */ ostream& print_on( ostream& o ) const; }; } // End of NameSpace MiniZinc #endiflibminizinc-2.4.2/include/minizinc/solvers/nl/nl_solreader.hh000066400000000000000000000102411360574160400243750ustar00rootroot00000000000000#ifndef __MINIZINC_NL_READ_SOL_HH__ #define __MINIZINC_NL_READ_SOL_HH__ #include #include #include #include #include #include using namespace std; // Reading a .sol file. // Note: I did not find any description of the format, so I did a bit of reverse engineering. // A sol file looks like this (first line is the 'message...' line) /* message from the solver Options 3 1 1 0 1 0 2 2 1 2 objno 0 0 */ // A sol file does not contains comments, and the blank line between the message and 'Options' is meaningfull. // Now, with our own comments. /* message from the solver # Starts on first line. Can span several line as long as their is no blank line # the blank line marks the end of the message Options # Inform about option used by the solver (?). May be absent. 3 # Number of options. 1 # opt 1 Note: I did not fully understand this, but reading "hooking your solver" 1 # opt 2 suggests that we can (probably) ignore that. 0 # opt 3 1 # Number A of dual before "suf_sos()" (before solving ?) 0 # Number of dual after. Seems to be either A or 0. Will probably always be 0 (???) 2 # Number B of primal before "suf_sos()" (before solving ?) 2 # Number of primal after. Seems to be either B or 0 1 # No dual. So this is the result for the first primal (variable indice 0) 2 # result for variable indice 1 objno 0 0 # Objectif 0 */ // Result code can be : // (from https://github.com/ampl/mp/blob/master/include/mp/common.h) // UNKNOWN = -1, // SOLVED = 0, // Optimal sol found for an optim problem or a feasible solution found for a satisfaction problem. // UNCERTAIN = 100, // Solution returned but it can be non-optimal or even infeasible. // INFEASIBLE = 200, // UNBOUNDED = 300, // Problem is unbounded. // LIMIT = 400, // Stopped by a limit, e.g. on iterations or time. // FAILURE = 500, // A solver error. // INTERRUPTED = 600 // Interrupted by the user. namespace MiniZinc { /** Declaration of the exit codes. */ enum NL_Solver_Status { PARSE_ERROR = -2, // We are adding our own error code for parsing UNKNOWN = -1, SOLVED = 0, // Optimal sol found for an optim problem or a feasible solution found for a satisfaction problem. UNCERTAIN = 100, // Solution returned but it can be non-optimal or even infeasible. INFEASIBLE = 200, UNBOUNDED = 300, // Problem is unbounded. LIMIT = 400, // Stopped by a limit, e.g. on iterations or time. FAILURE = 500, // A solver error. INTERRUPTED = 600 // Interrupted by the user. }; /** Represent a solution read from a file '.sol'. */ class NLSol { public: // --- --- --- Fields string message; NL_Solver_Status status; vector values; // --- --- --- Constructors NLSol() = default; NLSol(string mes, NL_Solver_Status st, vector res): message(mes), status(st), values(res) {} // --- --- --- Static functions static NLSol parse_sol(std::istream &in); }; /** Our version of Solns2Out **/ class NLSolns2Out { private: Solns2Out* out; NLFile& nl_file; std::ofstream dummy_ofstream; // Controls for feedRawDataChunk bool in_line; bool verbose; public: NLSolns2Out(Solns2Out* out0, NLFile& nl_file0, bool verbose0) : out(out0), nl_file(nl_file0), in_line(false), verbose(verbose0) {} void parse_sol(const string& filename); bool feedRawDataChunk(const char* data); std::ostream& getLog(void); }; } #endif libminizinc-2.4.2/include/minizinc/solvers/nl/nl_solverfactory.hh000066400000000000000000000007431360574160400253250ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_NL_SOLVERFACTORY_HH__ #define __MINIZINC_NL_SOLVERFACTORY_HH__ namespace MiniZinc { class NL_SolverFactoryInitialiser { public: NL_SolverFactoryInitialiser(void); }; } #endif libminizinc-2.4.2/include/minizinc/solvers/nl/nl_solverinstance.hh000066400000000000000000000041121360574160400254540ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_NL_SOLVER_INSTANCE_HH__ #define __MINIZINC_NL_SOLVER_INSTANCE_HH__ #include #include #include #include #ifdef _WIN32 #undef ERROR #endif namespace MiniZinc { class NLSolverOptions : public SolverInstanceBase::Options { public: std::string nl_solver; std::vector nl_flags; std::vector nl_solver_flags; bool do_hexafloat = false; bool do_keepfile = false; }; class NLSolverInstance : public SolverInstanceBase { private: std::string _fzn_solver; protected: Model* _fzn; Model* _ozn; NLFile nl_file; public: NLSolverInstance(Env& env, std::ostream& log, SolverInstanceBase::Options* opt); ~NLSolverInstance(void); Status next(void) {return SolverInstance::Status::ERROR;} Status solve(void); void processFlatZinc(void); void resetSolver(void); protected: Expression* getSolutionValue(Id* id); void analyse(const Item* i); }; class NL_SolverFactory: public SolverFactory { protected: virtual SolverInstanceBase* doCreateSI(Env& env, std::ostream& log, SolverInstanceBase::Options* opt); public: NL_SolverFactory(void); virtual SolverInstanceBase::Options* createOptions(void); virtual std::string getDescription(SolverInstanceBase::Options* opt=NULL); virtual std::string getVersion(SolverInstanceBase::Options* opt=NULL); virtual std::string getId(void); virtual bool processOption(SolverInstanceBase::Options* opt, int& i, std::vector& argv); virtual void printHelp(std::ostream& os); //void setAcceptedFlags(SolverInstanceBase::Options* opt, const std::vector& flags); }; } #endif libminizinc-2.4.2/include/minizinc/statistics.hh000066400000000000000000000023621360574160400220150ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_STATISTICS_HH__ #define __MINIZINC_STATISTICS_HH__ #include namespace MiniZinc { class Statistics { protected: // time in milliseconds unsigned long long _time; // search nodes unsigned long long _nodes; // failures/ backtracks unsigned long long _failures; // current objective value double _objective; public: Statistics() : _time(0), _nodes(0), _failures(0) {} virtual void print(std::ostream& os); void time(unsigned long long t); void nodes(unsigned long long n); void failures(unsigned long long f); void objective(double o); unsigned long long time(); unsigned long long nodes(); unsigned long long failures(); double objective(); Statistics& operator+=(Statistics& s); virtual void cleanup() { _time = _nodes = _failures = 0; } }; } #endif libminizinc-2.4.2/include/minizinc/support/000077500000000000000000000000001360574160400210135ustar00rootroot00000000000000libminizinc-2.4.2/include/minizinc/support/regex.hh000066400000000000000000000025711360574160400224530ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Jip J. Dekker */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_REGEX_HH__ #define __MINIZINC_REGEX_HH__ #ifdef HAS_GECODE // Regex Parser Requirements #include #include #include #include #include // This is a workaround for a bug in flex that only shows up // with the Microsoft C++ compiler #if defined(_MSC_VER) #define YY_NO_UNISTD_H #ifdef __cplusplus extern "C" int isatty(int); #endif #endif // The Microsoft C++ compiler marks certain functions as deprecated, // so let's take the alternative definitions #if defined(_MSC_VER) #define strdup _strdup #define fileno _fileno #endif //Anonymous struct for when yyparse is exported typedef struct REContext REContext; // Parser generated header #include using namespace Gecode; using namespace MiniZinc; // Parsing function std::unique_ptr regex_from_string(const std::string& expression, const IntSetVal& domain, const std::unordered_map& identifiers); #endif //HAS_GECODE #endif //__MINIZINC_REGEX_HH__ libminizinc-2.4.2/include/minizinc/thirdparty/000077500000000000000000000000001360574160400214715ustar00rootroot00000000000000libminizinc-2.4.2/include/minizinc/thirdparty/b64/000077500000000000000000000000001360574160400220645ustar00rootroot00000000000000libminizinc-2.4.2/include/minizinc/thirdparty/b64/cdecode.h000066400000000000000000000012111360574160400236160ustar00rootroot00000000000000/* cdecode.h - c header for a base64 decoding algorithm This is part of the libb64 project, and has been placed in the public domain. For details, see http://sourceforge.net/projects/libb64 */ #ifndef BASE64_CDECODE_H #define BASE64_CDECODE_H typedef enum { step_a, step_b, step_c, step_d } base64_decodestep; typedef struct { base64_decodestep step; char plainchar; } base64_decodestate; void base64_init_decodestate(base64_decodestate* state_in); int base64_decode_value(char value_in); int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in); #endif /* BASE64_CDECODE_H */ libminizinc-2.4.2/include/minizinc/thirdparty/b64/cencode.h000066400000000000000000000013241360574160400236350ustar00rootroot00000000000000/* cencode.h - c header for a base64 encoding algorithm This is part of the libb64 project, and has been placed in the public domain. For details, see http://sourceforge.net/projects/libb64 */ #ifndef BASE64_CENCODE_H #define BASE64_CENCODE_H typedef enum { step_A, step_B, step_C } base64_encodestep; typedef struct { base64_encodestep step; char result; int stepcount; } base64_encodestate; void base64_init_encodestate(base64_encodestate* state_in); char base64_encode_value(char value_in); int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in); int base64_encode_blockend(char* code_out, base64_encodestate* state_in); #endif /* BASE64_CENCODE_H */ libminizinc-2.4.2/include/minizinc/thirdparty/b64/decode.h000066400000000000000000000026161360574160400234650ustar00rootroot00000000000000// :mode=c++: /* decode.h - c++ wrapper for a base64 decoding algorithm This is part of the libb64 project, and has been placed in the public domain. For details, see http://sourceforge.net/projects/libb64 */ #ifndef BASE64_DECODE_H #define BASE64_DECODE_H #define BUFFERSIZE 4096 #include namespace base64 { extern "C" { #include } struct decoder { base64_decodestate _state; int _buffersize; decoder(int buffersize_in = BUFFERSIZE) : _buffersize(buffersize_in) {} int decode(char value_in) { return base64_decode_value(value_in); } int decode(const char* code_in, const int length_in, char* plaintext_out) { return base64_decode_block(code_in, length_in, plaintext_out, &_state); } void decode(std::istream& istream_in, std::ostream& ostream_in) { base64_init_decodestate(&_state); // const int N = _buffersize; char* code = new char[N]; char* plaintext = new char[N]; int codelength; int plainlength; do { istream_in.read((char*)code, N); codelength = istream_in.gcount(); plainlength = decode(code, codelength, plaintext); ostream_in.write((const char*)plaintext, plainlength); } while (istream_in.good() && codelength > 0); // base64_init_decodestate(&_state); delete [] code; delete [] plaintext; } }; } // namespace base64 #endif // BASE64_DECODE_H libminizinc-2.4.2/include/minizinc/thirdparty/b64/encode.h000066400000000000000000000030661360574160400234770ustar00rootroot00000000000000// :mode=c++: /* encode.h - c++ wrapper for a base64 encoding algorithm This is part of the libb64 project, and has been placed in the public domain. For details, see http://sourceforge.net/projects/libb64 */ #ifndef BASE64_ENCODE_H #define BASE64_ENCODE_H #define BUFFERSIZE 4096 #include namespace base64 { extern "C" { #include } struct encoder { base64_encodestate _state; int _buffersize; encoder(int buffersize_in = BUFFERSIZE) : _buffersize(buffersize_in) {} int encode(char value_in) { return base64_encode_value(value_in); } int encode(const char* code_in, const int length_in, char* plaintext_out) { return base64_encode_block(code_in, length_in, plaintext_out, &_state); } int encode_end(char* plaintext_out) { return base64_encode_blockend(plaintext_out, &_state); } void encode(std::istream& istream_in, std::ostream& ostream_in) { base64_init_encodestate(&_state); // const int N = _buffersize; char* plaintext = new char[N]; char* code = new char[2*N]; int plainlength; int codelength; do { istream_in.read(plaintext, N); plainlength = istream_in.gcount(); // codelength = encode(plaintext, plainlength, code); ostream_in.write(code, codelength); } while (istream_in.good() && plainlength > 0); codelength = encode_end(code); ostream_in.write(code, codelength); // base64_init_encodestate(&_state); delete [] code; delete [] plaintext; } }; } // namespace base64 #endif // BASE64_ENCODE_H libminizinc-2.4.2/include/minizinc/thirdparty/miniz.h000066400000000000000000002025651360574160400230020ustar00rootroot00000000000000/* miniz.c 2.0.7 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing See "unlicense" statement at the end of this file. Rich Geldreich , last updated Oct. 13, 2013 Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). * Low-level Deflate/Inflate implementation notes: Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses approximately as well as zlib. Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory block large enough to hold the entire file. The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. * zlib-style API notes: miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in zlib replacement in many apps: The z_stream struct, optional memory allocation callbacks deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound inflateInit/inflateInit2/inflate/inflateEnd compress, compress2, compressBound, uncompress CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. Supports raw deflate streams or standard zlib streams with adler-32 checking. Limitations: The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but there are no guarantees that miniz.c pulls this off perfectly. * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by Alex Evans. Supports 1-4 bytes/pixel images. * ZIP archive API notes: The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to get the job done with minimal fuss. There are simple API's to retrieve file information, read files from existing archives, create new archives, append new files to existing archives, or clone archive data from one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), or you can specify custom file read/write callbacks. - Archive reading: Just call this function to read a single file from a disk archive: void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint zip_flags); For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); The locate operation can optionally check file comments too, which (as one example) can be used to identify multiple versions of the same file in an archive. This function uses a simple linear search through the central directory, so it's not very fast. Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and retrieve detailed info on each file by calling mz_zip_reader_file_stat(). - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data to disk and builds an exact image of the central directory in memory. The central directory image is written all at once at the end of the archive file when the archive is finalized. The archive writer can optionally align each file's local header and file data to any power of 2 alignment, which can be useful when the archive will be read from optical media. Also, the writer supports placing arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still readable by any ZIP tool. - Archive appending: The simple way to add a single file to an archive is to call this function: mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); The archive will be created if it doesn't already exist, otherwise it'll be appended to. Note the appending is done in-place and is not an atomic operation, so if something goes wrong during the operation it's possible the archive could be left without a central directory (although the local file headers and file data will be fine, so the archive will be recoverable). For more complex archive modification scenarios: 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and you're done. This is safe but requires a bunch of temporary disk space or heap memory. 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), append new files as needed, then finalize the archive which will write an updated central directory to the original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a possibility that the archive's central directory could be lost with this method if anything goes wrong, though. - ZIP archive support limitations: No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files. Requires streams capable of seeking. * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. * Important: For best perf. be sure to customize the below macros for your target platform: #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 #define MINIZ_LITTLE_ENDIAN 1 #define MINIZ_HAS_64BIT_REGISTERS 1 * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). */ #pragma once /* Defines to completely disable specific portions of miniz.c: If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. */ /* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. */ /*#define MINIZ_NO_STDIO */ /* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or */ /* get/set file times, and the C run-time funcs that get/set times won't be called. */ /* The current downside is the times written to your archives will be from 1979. */ /*#define MINIZ_NO_TIME */ /* Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. */ /*#define MINIZ_NO_ARCHIVE_APIS */ /* Define MINIZ_NO_ARCHIVE_WRITING_APIS to disable all writing related ZIP archive API's. */ /*#define MINIZ_NO_ARCHIVE_WRITING_APIS */ /* Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. */ /*#define MINIZ_NO_ZLIB_APIS */ /* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. */ /*#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ /* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. */ /*#define MINIZ_NO_MALLOC */ #if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) /* TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux */ #define MINIZ_NO_TIME #endif #include #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) #include #endif #if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) /* MINIZ_X86_OR_X64_CPU is only used to help set the below macros. */ #define MINIZ_X86_OR_X64_CPU 1 #else #define MINIZ_X86_OR_X64_CPU 0 #endif #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU /* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */ #define MINIZ_LITTLE_ENDIAN 1 #else #define MINIZ_LITTLE_ENDIAN 0 #endif #if MINIZ_X86_OR_X64_CPU /* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */ #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 #else #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 #endif #if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) /* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). */ #define MINIZ_HAS_64BIT_REGISTERS 1 #else #define MINIZ_HAS_64BIT_REGISTERS 0 #endif #ifdef __cplusplus extern "C" { #endif /* ------------------- zlib-style API Definitions. */ /* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! */ typedef unsigned long mz_ulong; /* mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. */ void mz_free(void *p); #define MZ_ADLER32_INIT (1) /* mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. */ mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); #define MZ_CRC32_INIT (0) /* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */ mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); /* Compression strategies. */ enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 }; /* Method */ #define MZ_DEFLATED 8 /* Heap allocation callbacks. Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. */ typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); typedef void (*mz_free_func)(void *opaque, void *address); typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); /* Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */ enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 }; #define MZ_VERSION "10.0.2" #define MZ_VERNUM 0xA020 #define MZ_VER_MAJOR 10 #define MZ_VER_MINOR 0 #define MZ_VER_REVISION 2 #define MZ_VER_SUBREVISION 0 #ifndef MINIZ_NO_ZLIB_APIS /* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). */ enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 }; /* Return status codes. MZ_PARAM_ERROR is non-standard. */ enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 }; /* Window bits */ #define MZ_DEFAULT_WINDOW_BITS 15 struct mz_internal_state; /* Compression/decompression stream struct. */ typedef struct mz_stream_s { const unsigned char *next_in; /* pointer to next byte to read */ unsigned int avail_in; /* number of bytes available at next_in */ mz_ulong total_in; /* total number of bytes consumed so far */ unsigned char *next_out; /* pointer to next byte to write */ unsigned int avail_out; /* number of bytes that can be written to next_out */ mz_ulong total_out; /* total number of bytes produced so far */ char *msg; /* error msg (unused) */ struct mz_internal_state *state; /* internal state, allocated by zalloc/zfree */ mz_alloc_func zalloc; /* optional heap allocation function (defaults to malloc) */ mz_free_func zfree; /* optional heap free function (defaults to free) */ void *opaque; /* heap alloc function user pointer */ int data_type; /* data_type (unused) */ mz_ulong adler; /* adler32 of the source or uncompressed data */ mz_ulong reserved; /* not used */ } mz_stream; typedef mz_stream *mz_streamp; /* Returns the version string of miniz.c. */ const char *mz_version(void); /* mz_deflateInit() initializes a compressor with default options: */ /* Parameters: */ /* pStream must point to an initialized mz_stream struct. */ /* level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. */ /* level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. */ /* (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) */ /* Return values: */ /* MZ_OK on success. */ /* MZ_STREAM_ERROR if the stream is bogus. */ /* MZ_PARAM_ERROR if the input parameters are bogus. */ /* MZ_MEM_ERROR on out of memory. */ int mz_deflateInit(mz_streamp pStream, int level); /* mz_deflateInit2() is like mz_deflate(), except with more control: */ /* Additional parameters: */ /* method must be MZ_DEFLATED */ /* window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) */ /* mem_level must be between [1, 9] (it's checked but ignored by miniz.c) */ int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); /* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */ int mz_deflateReset(mz_streamp pStream); /* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. */ /* Parameters: */ /* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ /* flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. */ /* Return values: */ /* MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). */ /* MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. */ /* MZ_STREAM_ERROR if the stream is bogus. */ /* MZ_PARAM_ERROR if one of the parameters is invalid. */ /* MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) */ int mz_deflate(mz_streamp pStream, int flush); /* mz_deflateEnd() deinitializes a compressor: */ /* Return values: */ /* MZ_OK on success. */ /* MZ_STREAM_ERROR if the stream is bogus. */ int mz_deflateEnd(mz_streamp pStream); /* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */ mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); /* Single-call compression functions mz_compress() and mz_compress2(): */ /* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */ int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); /* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). */ mz_ulong mz_compressBound(mz_ulong source_len); /* Initializes a decompressor. */ int mz_inflateInit(mz_streamp pStream); /* mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: */ /* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). */ int mz_inflateInit2(mz_streamp pStream, int window_bits); /* Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. */ /* Parameters: */ /* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ /* flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. */ /* On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). */ /* MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. */ /* Return values: */ /* MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. */ /* MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. */ /* MZ_STREAM_ERROR if the stream is bogus. */ /* MZ_DATA_ERROR if the deflate stream is invalid. */ /* MZ_PARAM_ERROR if one of the parameters is invalid. */ /* MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again */ /* with more input data, or with more room in the output buffer (except when using single call decompression, described above). */ int mz_inflate(mz_streamp pStream, int flush); /* Deinitializes a decompressor. */ int mz_inflateEnd(mz_streamp pStream); /* Single-call decompression. */ /* Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. */ int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); /* Returns a string description of the specified error code, or NULL if the error code is invalid. */ const char *mz_error(int err); /* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. */ /* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */ #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES typedef unsigned char Byte; typedef unsigned int uInt; typedef mz_ulong uLong; typedef Byte Bytef; typedef uInt uIntf; typedef char charf; typedef int intf; typedef void *voidpf; typedef uLong uLongf; typedef void *voidp; typedef void *const voidpc; #define Z_NULL 0 #define Z_NO_FLUSH MZ_NO_FLUSH #define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH #define Z_SYNC_FLUSH MZ_SYNC_FLUSH #define Z_FULL_FLUSH MZ_FULL_FLUSH #define Z_FINISH MZ_FINISH #define Z_BLOCK MZ_BLOCK #define Z_OK MZ_OK #define Z_STREAM_END MZ_STREAM_END #define Z_NEED_DICT MZ_NEED_DICT #define Z_ERRNO MZ_ERRNO #define Z_STREAM_ERROR MZ_STREAM_ERROR #define Z_DATA_ERROR MZ_DATA_ERROR #define Z_MEM_ERROR MZ_MEM_ERROR #define Z_BUF_ERROR MZ_BUF_ERROR #define Z_VERSION_ERROR MZ_VERSION_ERROR #define Z_PARAM_ERROR MZ_PARAM_ERROR #define Z_NO_COMPRESSION MZ_NO_COMPRESSION #define Z_BEST_SPEED MZ_BEST_SPEED #define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION #define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION #define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY #define Z_FILTERED MZ_FILTERED #define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY #define Z_RLE MZ_RLE #define Z_FIXED MZ_FIXED #define Z_DEFLATED MZ_DEFLATED #define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS #define alloc_func mz_alloc_func #define free_func mz_free_func #define internal_state mz_internal_state #define z_stream mz_stream #define deflateInit mz_deflateInit #define deflateInit2 mz_deflateInit2 #define deflateReset mz_deflateReset #define deflate mz_deflate #define deflateEnd mz_deflateEnd #define deflateBound mz_deflateBound #define compress mz_compress #define compress2 mz_compress2 #define compressBound mz_compressBound #define inflateInit mz_inflateInit #define inflateInit2 mz_inflateInit2 #define inflate mz_inflate #define inflateEnd mz_inflateEnd #define uncompress mz_uncompress #define crc32 mz_crc32 #define adler32 mz_adler32 #define MAX_WBITS 15 #define MAX_MEM_LEVEL 9 #define zError mz_error #define ZLIB_VERSION MZ_VERSION #define ZLIB_VERNUM MZ_VERNUM #define ZLIB_VER_MAJOR MZ_VER_MAJOR #define ZLIB_VER_MINOR MZ_VER_MINOR #define ZLIB_VER_REVISION MZ_VER_REVISION #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION #define zlibVersion mz_version #define zlib_version mz_version() #endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ #endif /* MINIZ_NO_ZLIB_APIS */ #ifdef __cplusplus } #endif #pragma once #include #include #include #include /* ------------------- Types and macros */ typedef unsigned char mz_uint8; typedef signed short mz_int16; typedef unsigned short mz_uint16; typedef unsigned int mz_uint32; typedef unsigned int mz_uint; typedef int64_t mz_int64; typedef uint64_t mz_uint64; typedef int mz_bool; #define MZ_FALSE (0) #define MZ_TRUE (1) /* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */ #ifdef _MSC_VER #define MZ_MACRO_END while (0, 0) #else #define MZ_MACRO_END while (0) #endif #ifdef MINIZ_NO_STDIO #define MZ_FILE void * #else #include #define MZ_FILE FILE #endif /* #ifdef MINIZ_NO_STDIO */ #ifdef MINIZ_NO_TIME typedef struct mz_dummy_time_t_tag { int m_dummy; } mz_dummy_time_t; #define MZ_TIME_T mz_dummy_time_t #else #define MZ_TIME_T time_t #endif #define MZ_ASSERT(x) assert(x) #ifdef MINIZ_NO_MALLOC #define MZ_MALLOC(x) NULL #define MZ_FREE(x) (void)x, ((void)0) #define MZ_REALLOC(p, x) NULL #else #define MZ_MALLOC(x) malloc(x) #define MZ_FREE(x) free(x) #define MZ_REALLOC(p, x) realloc(p, x) #endif #define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN #define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) #define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) #else #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) #endif #define MZ_READ_LE64(p) (((mz_uint64)MZ_READ_LE32(p)) | (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) << 32U)) #ifdef _MSC_VER #define MZ_FORCEINLINE __forceinline #elif defined(__GNUC__) #define MZ_FORCEINLINE __inline__ __attribute__((__always_inline__)) #else #define MZ_FORCEINLINE inline #endif #ifdef __cplusplus extern "C" { #endif extern void *miniz_def_alloc_func(void *opaque, size_t items, size_t size); extern void miniz_def_free_func(void *opaque, void *address); extern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); #define MZ_UINT16_MAX (0xFFFFU) #define MZ_UINT32_MAX (0xFFFFFFFFU) #ifdef __cplusplus } #endif #pragma once #ifdef __cplusplus extern "C" { #endif /* ------------------- Low-level Compression API Definitions */ /* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). */ #define TDEFL_LESS_MEMORY 0 /* tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): */ /* TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). */ enum { TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF }; /* TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. */ /* TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). */ /* TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. */ /* TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). */ /* TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) */ /* TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. */ /* TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. */ /* TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. */ /* The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). */ enum { TDEFL_WRITE_ZLIB_HEADER = 0x01000, TDEFL_COMPUTE_ADLER32 = 0x02000, TDEFL_GREEDY_PARSING_FLAG = 0x04000, TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, TDEFL_RLE_MATCHES = 0x10000, TDEFL_FILTER_MATCHES = 0x20000, TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 }; /* High level compression functions: */ /* tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). */ /* On entry: */ /* pSrc_buf, src_buf_len: Pointer and size of source block to compress. */ /* flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. */ /* On return: */ /* Function returns a pointer to the compressed data, or NULL on failure. */ /* *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. */ /* The caller must free() the returned block when it's no longer needed. */ void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); /* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */ /* Returns 0 on failure. */ size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); /* Compresses an image to a compressed PNG file in memory. */ /* On entry: */ /* pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. */ /* The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. */ /* level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL */ /* If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). */ /* On return: */ /* Function returns a pointer to the compressed data, or NULL on failure. */ /* *pLen_out will be set to the size of the PNG image file. */ /* The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. */ void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); /* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */ typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); /* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. */ mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 }; /* TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). */ #if TDEFL_LESS_MEMORY enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; #else enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; #endif /* The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. */ typedef enum { TDEFL_STATUS_BAD_PARAM = -2, TDEFL_STATUS_PUT_BUF_FAILED = -1, TDEFL_STATUS_OKAY = 0, TDEFL_STATUS_DONE = 1 } tdefl_status; /* Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums */ typedef enum { TDEFL_NO_FLUSH = 0, TDEFL_SYNC_FLUSH = 2, TDEFL_FULL_FLUSH = 3, TDEFL_FINISH = 4 } tdefl_flush; /* tdefl's compression state structure. */ typedef struct { tdefl_put_buf_func_ptr m_pPut_buf_func; void *m_pPut_buf_user; mz_uint m_flags, m_max_probes[2]; int m_greedy_parsing; mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; tdefl_status m_prev_return_status; const void *m_pIn_buf; void *m_pOut_buf; size_t *m_pIn_buf_size, *m_pOut_buf_size; tdefl_flush m_flush; const mz_uint8 *m_pSrc; size_t m_src_buf_left, m_out_buf_ofs; mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; } tdefl_compressor; /* Initializes the compressor. */ /* There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. */ /* pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. */ /* If pBut_buf_func is NULL the user should always call the tdefl_compress() API. */ /* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) */ tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); /* Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. */ tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); /* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */ /* tdefl_compress_buffer() always consumes the entire input buffer. */ tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); mz_uint32 tdefl_get_adler32(tdefl_compressor *d); /* Create tdefl_compress() flags given zlib-style compression parameters. */ /* level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) */ /* window_bits may be -15 (raw deflate) or 15 (zlib) */ /* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED */ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); /* Allocate the tdefl_compressor structure in C so that */ /* non-C language bindings to tdefl_ API don't need to worry about */ /* structure size and allocation mechanism. */ tdefl_compressor *tdefl_compressor_alloc(); void tdefl_compressor_free(tdefl_compressor *pComp); #ifdef __cplusplus } #endif #pragma once /* ------------------- Low-level Decompression API Definitions */ #ifdef __cplusplus extern "C" { #endif /* Decompression flags used by tinfl_decompress(). */ /* TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. */ /* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. */ /* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). */ /* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. */ enum { TINFL_FLAG_PARSE_ZLIB_HEADER = 1, TINFL_FLAG_HAS_MORE_INPUT = 2, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, TINFL_FLAG_COMPUTE_ADLER32 = 8 }; /* High level decompression functions: */ /* tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). */ /* On entry: */ /* pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. */ /* On return: */ /* Function returns a pointer to the decompressed data, or NULL on failure. */ /* *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. */ /* The caller must call mz_free() on the returned block when it's no longer needed. */ void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); /* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */ /* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */ #define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); /* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. */ /* Returns 1 on success or 0 on failure. */ typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor; /* Allocate the tinfl_decompressor structure in C so that */ /* non-C language bindings to tinfl_ API don't need to worry about */ /* structure size and allocation mechanism. */ tinfl_decompressor *tinfl_decompressor_alloc(); void tinfl_decompressor_free(tinfl_decompressor *pDecomp); /* Max size of LZ dictionary. */ #define TINFL_LZ_DICT_SIZE 32768 /* Return status. */ typedef enum { /* This flags indicates the inflator needs 1 or more input bytes to make forward progress, but the caller is indicating that no more are available. The compressed data */ /* is probably corrupted. If you call the inflator again with more bytes it'll try to continue processing the input but this is a BAD sign (either the data is corrupted or you called it incorrectly). */ /* If you call it again with no input you'll just get TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS again. */ TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS = -4, /* This flag indicates that one or more of the input parameters was obviously bogus. (You can try calling it again, but if you get this error the calling code is wrong.) */ TINFL_STATUS_BAD_PARAM = -3, /* This flags indicate the inflator is finished but the adler32 check of the uncompressed data didn't match. If you call it again it'll return TINFL_STATUS_DONE. */ TINFL_STATUS_ADLER32_MISMATCH = -2, /* This flags indicate the inflator has somehow failed (bad code, corrupted input, etc.). If you call it again without resetting via tinfl_init() it it'll just keep on returning the same status failure code. */ TINFL_STATUS_FAILED = -1, /* Any status code less than TINFL_STATUS_DONE must indicate a failure. */ /* This flag indicates the inflator has returned every byte of uncompressed data that it can, has consumed every byte that it needed, has successfully reached the end of the deflate stream, and */ /* if zlib headers and adler32 checking enabled that it has successfully checked the uncompressed data's adler32. If you call it again you'll just get TINFL_STATUS_DONE over and over again. */ TINFL_STATUS_DONE = 0, /* This flag indicates the inflator MUST have more input data (even 1 byte) before it can make any more forward progress, or you need to clear the TINFL_FLAG_HAS_MORE_INPUT */ /* flag on the next call if you don't have any more source data. If the source data was somehow corrupted it's also possible (but unlikely) for the inflator to keep on demanding input to */ /* proceed, so be sure to properly set the TINFL_FLAG_HAS_MORE_INPUT flag. */ TINFL_STATUS_NEEDS_MORE_INPUT = 1, /* This flag indicates the inflator definitely has 1 or more bytes of uncompressed data available, but it cannot write this data into the output buffer. */ /* Note if the source compressed data was corrupted it's possible for the inflator to return a lot of uncompressed data to the caller. I've been assuming you know how much uncompressed data to expect */ /* (either exact or worst case) and will stop calling the inflator and fail after receiving too much. In pure streaming scenarios where you have no idea how many bytes to expect this may not be possible */ /* so I may need to add some code to address this. */ TINFL_STATUS_HAS_MORE_OUTPUT = 2 } tinfl_status; /* Initializes the decompressor to its initial state. */ #define tinfl_init(r) \ do \ { \ (r)->m_state = 0; \ } \ MZ_MACRO_END #define tinfl_get_adler32(r) (r)->m_check_adler32 /* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. */ /* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. */ tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); /* Internal/private bits follow. */ enum { TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS }; typedef struct { mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; } tinfl_huff_table; #if MINIZ_HAS_64BIT_REGISTERS #define TINFL_USE_64BIT_BITBUF 1 #else #define TINFL_USE_64BIT_BITBUF 0 #endif #if TINFL_USE_64BIT_BITBUF typedef mz_uint64 tinfl_bit_buf_t; #define TINFL_BITBUF_SIZE (64) #else typedef mz_uint32 tinfl_bit_buf_t; #define TINFL_BITBUF_SIZE (32) #endif struct tinfl_decompressor_tag { mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; tinfl_bit_buf_t m_bit_buf; size_t m_dist_from_out_buf_start; tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; }; #ifdef __cplusplus } #endif #pragma once /* ------------------- ZIP archive reading/writing */ #ifndef MINIZ_NO_ARCHIVE_APIS #ifdef __cplusplus extern "C" { #endif enum { /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */ MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 }; typedef struct { /* Central directory file index. */ mz_uint32 m_file_index; /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */ mz_uint64 m_central_dir_ofs; /* These fields are copied directly from the zip's central dir. */ mz_uint16 m_version_made_by; mz_uint16 m_version_needed; mz_uint16 m_bit_flag; mz_uint16 m_method; #ifndef MINIZ_NO_TIME MZ_TIME_T m_time; #endif /* CRC-32 of uncompressed data. */ mz_uint32 m_crc32; /* File's compressed size. */ mz_uint64 m_comp_size; /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ mz_uint64 m_uncomp_size; /* Zip internal and external file attributes. */ mz_uint16 m_internal_attr; mz_uint32 m_external_attr; /* Entry's local header file offset in bytes. */ mz_uint64 m_local_header_ofs; /* Size of comment in bytes. */ mz_uint32 m_comment_size; /* MZ_TRUE if the entry appears to be a directory. */ mz_bool m_is_directory; /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ mz_bool m_is_encrypted; /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ mz_bool m_is_supported; /* Filename. If string ends in '/' it's a subdirectory entry. */ /* Guaranteed to be zero terminated, may be truncated to fit. */ char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; /* Comment field. */ /* Guaranteed to be zero terminated, may be truncated to fit. */ char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; } mz_zip_archive_file_stat; typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); struct mz_zip_internal_state_tag; typedef struct mz_zip_internal_state_tag mz_zip_internal_state; typedef enum { MZ_ZIP_MODE_INVALID = 0, MZ_ZIP_MODE_READING = 1, MZ_ZIP_MODE_WRITING = 2, MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 } mz_zip_mode; typedef enum { MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000 } mz_zip_flags; typedef enum { MZ_ZIP_TYPE_INVALID = 0, MZ_ZIP_TYPE_USER, MZ_ZIP_TYPE_MEMORY, MZ_ZIP_TYPE_HEAP, MZ_ZIP_TYPE_FILE, MZ_ZIP_TYPE_CFILE, MZ_ZIP_TOTAL_TYPES } mz_zip_type; /* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */ typedef enum { MZ_ZIP_NO_ERROR = 0, MZ_ZIP_UNDEFINED_ERROR, MZ_ZIP_TOO_MANY_FILES, MZ_ZIP_FILE_TOO_LARGE, MZ_ZIP_UNSUPPORTED_METHOD, MZ_ZIP_UNSUPPORTED_ENCRYPTION, MZ_ZIP_UNSUPPORTED_FEATURE, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, MZ_ZIP_NOT_AN_ARCHIVE, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, MZ_ZIP_UNSUPPORTED_MULTIDISK, MZ_ZIP_DECOMPRESSION_FAILED, MZ_ZIP_COMPRESSION_FAILED, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, MZ_ZIP_CRC_CHECK_FAILED, MZ_ZIP_UNSUPPORTED_CDIR_SIZE, MZ_ZIP_ALLOC_FAILED, MZ_ZIP_FILE_OPEN_FAILED, MZ_ZIP_FILE_CREATE_FAILED, MZ_ZIP_FILE_WRITE_FAILED, MZ_ZIP_FILE_READ_FAILED, MZ_ZIP_FILE_CLOSE_FAILED, MZ_ZIP_FILE_SEEK_FAILED, MZ_ZIP_FILE_STAT_FAILED, MZ_ZIP_INVALID_PARAMETER, MZ_ZIP_INVALID_FILENAME, MZ_ZIP_BUF_TOO_SMALL, MZ_ZIP_INTERNAL_ERROR, MZ_ZIP_FILE_NOT_FOUND, MZ_ZIP_ARCHIVE_TOO_LARGE, MZ_ZIP_VALIDATION_FAILED, MZ_ZIP_WRITE_CALLBACK_FAILED, MZ_ZIP_TOTAL_ERRORS } mz_zip_error; typedef struct { mz_uint64 m_archive_size; mz_uint64 m_central_directory_file_ofs; /* We only support up to UINT32_MAX files in zip64 mode. */ mz_uint32 m_total_files; mz_zip_mode m_zip_mode; mz_zip_type m_zip_type; mz_zip_error m_last_error; mz_uint64 m_file_offset_alignment; mz_alloc_func m_pAlloc; mz_free_func m_pFree; mz_realloc_func m_pRealloc; void *m_pAlloc_opaque; mz_file_read_func m_pRead; mz_file_write_func m_pWrite; mz_file_needs_keepalive m_pNeeds_keepalive; void *m_pIO_opaque; mz_zip_internal_state *m_pState; } mz_zip_archive; typedef struct { mz_zip_archive *pZip; mz_uint flags; int status; #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS mz_uint file_crc32; #endif mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; mz_zip_archive_file_stat file_stat; void *pRead_buf; void *pWrite_buf; size_t out_blk_remain; tinfl_decompressor inflator; } mz_zip_reader_extract_iter_state; /* -------- ZIP reading */ /* Inits a ZIP archive reader. */ /* These functions read and validate the archive's central directory. */ mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); #ifndef MINIZ_NO_STDIO /* Read a archive from a disk file. */ /* file_start_ofs is the file offset where the archive actually begins, or 0. */ /* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. If zero the entire file is treated as the archive. */ mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); /* Read an archive from an already opened FILE, beginning at the current file position. */ /* The archive is assumed to be archive_size bytes long. If archive_size is < 0, then the entire rest of the file is assumed to contain the archive. */ /* The FILE will NOT be closed when mz_zip_reader_end() is called. */ mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); #endif /* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. */ mz_bool mz_zip_reader_end(mz_zip_archive *pZip); /* -------- ZIP reading or writing */ /* Clears a mz_zip_archive struct to all zeros. */ /* Important: This must be done before passing the struct to any mz_zip functions. */ void mz_zip_zero_struct(mz_zip_archive *pZip); mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); /* Returns the total number of files in the archive. */ mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); /* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */ size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); /* Attempts to locates a file in the archive's central directory. */ /* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ /* Returns -1 if the file cannot be found. */ int mz_zip_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); /* Returns MZ_FALSE if the file cannot be found. */ mz_bool mz_zip_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex); /* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this field. */ /* Note that the m_last_error functionality is not thread safe. */ mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); const char *mz_zip_get_error_string(mz_zip_error mz_err); /* MZ_TRUE if the archive file entry is a directory entry. */ mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); /* MZ_TRUE if the file is encrypted/strong encrypted. */ mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); /* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch file. */ mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); /* Retrieves the filename of an archive file entry. */ /* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. */ mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); /* Attempts to locates a file in the archive's central directory. */ /* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ /* Returns -1 if the file cannot be found. */ int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); int mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); /* Returns detailed information about an archive file entry. */ mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); /* MZ_TRUE if the file is in zip64 format. */ /* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 extended file information fields in the central directory. */ mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); /* Returns the total central directory size in bytes. */ /* The current max supported size is <= MZ_UINT32_MAX. */ size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); /* Extracts a archive file to a memory buffer using no memory allocation. */ /* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */ mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); /* Extracts a archive file to a memory buffer. */ mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); /* Extracts a archive file to a dynamically allocated heap buffer. */ /* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */ /* Returns NULL and sets the last error on failure. */ void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); /* Extracts a archive file using a callback function to output the file's data. */ mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); /* Extract a file iteratively */ mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size); mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); #ifndef MINIZ_NO_STDIO /* Extracts a archive file to a disk file and sets its last accessed and modified times. */ /* This function only extracts files, not archive directory records. */ mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); /* Extracts a archive file starting at the current position in the destination FILE stream. */ mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); #endif #if 0 /* TODO */ typedef void *mz_zip_streaming_extract_state_ptr; mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); uint64_t mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); uint64_t mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, uint64_t new_ofs); size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size); mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); #endif /* This function compares the archive's local headers, the optional local zip64 extended information block, and the optional descriptor following the compressed data vs. the data in the central directory. */ /* It also validates that each file can be successfully uncompressed unless the MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY is specified. */ mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); /* Validates an entire archive by calling mz_zip_validate_file() on each file. */ mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags); /* Misc utils/helpers, valid for ZIP reading or writing */ mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr); mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr); /* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */ mz_bool mz_zip_end(mz_zip_archive *pZip); /* -------- ZIP writing */ #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS /* Inits a ZIP archive writer. */ /*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init or mz_zip_writer_init_v2*/ /*The output is streamable, i.e. file_ofs in mz_file_write_func always increases only by n*/ mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); #ifndef MINIZ_NO_STDIO mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); #endif /* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. */ /* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. */ /* For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). */ /* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. */ /* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before */ /* the archive is finalized the file's central directory will be hosed. */ mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); /* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. */ /* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */ /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); /* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with already compressed data. */ /* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */ mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len); #ifndef MINIZ_NO_STDIO /* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. */ /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); /* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */ mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len); #endif /* Adds a file to an archive by fully cloning the data from another archive. */ /* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the compressed data. */ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index); /* Finalizes the archive by writing the central directory records followed by the end of central directory record. */ /* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */ /* An archive must be manually finalized by calling this function for it to be valid. */ mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); /* Finalizes a heap archive, returning a poiner to the heap block and its size. */ /* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */ mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); /* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */ /* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). */ mz_bool mz_zip_writer_end(mz_zip_archive *pZip); /* -------- Misc. high-level helper functions: */ /* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. */ /* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up state (without a central directory). */ /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ /* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate the file (so the old central dir would be at the end) if something goes wrong. */ mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); /* Reads a single file from an archive into a heap block. */ /* If pComment is not NULL, only the file with the specified comment will be extracted. */ /* Returns NULL on failure. */ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ #ifdef __cplusplus } #endif #endif /* MINIZ_NO_ARCHIVE_APIS */ libminizinc-2.4.2/include/minizinc/timer.hh000066400000000000000000000025441360574160400207450ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_TIMER_HH__ #define __MINIZINC_TIMER_HH__ #include #include #include #include #include namespace MiniZinc { class Timer { protected: std::chrono::steady_clock::time_point last; public: /// Construct timer Timer(void) : last(std::chrono::steady_clock::now()) {} /// Reset timer void reset(void) { last = std::chrono::steady_clock::now(); } /// Return milliseconds since timer was last reset long long int ms(void) const { return std::chrono::duration_cast(std::chrono::steady_clock::now()-last).count(); } /// Return seconds since timer was last reset double s(void) const { return std::chrono::duration_cast >(std::chrono::steady_clock::now()-last).count(); } std::string stoptime(void) const { std::ostringstream oss; oss << std::setprecision(2) << std::fixed << s() << " s"; return oss.str(); } }; } #endif libminizinc-2.4.2/include/minizinc/type.hh000066400000000000000000000240311360574160400206010ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_TYPE_HH__ #define __MINIZINC_TYPE_HH__ #include #include #include namespace MiniZinc { class EnvI; /// Type of a MiniZinc expression class Type { public: /// Type-inst enum TypeInst { TI_PAR, TI_VAR }; /// Basic type enum BaseType { BT_BOOL, BT_INT, BT_FLOAT, BT_STRING, BT_ANN, BT_TOP, BT_BOT, BT_UNKNOWN }; /// Whether the expression is plain or set enum SetType { ST_PLAIN, ST_SET }; /// Whether the expression is normal or optional enum OptType { OT_PRESENT, OT_OPTIONAL }; /// Whether the par expression contains a var argument enum ContainsVarType { CV_NO, CV_YES }; private: unsigned int _ti : 1; unsigned int _bt : 4; unsigned int _st : 1; unsigned int _ot : 1; unsigned int _cv : 1; /** \brief Enumerated type identifier * This is an index into a table in the Env. It is currently limited to * 4095 different enumerated type identifiers. * For a non-array type, this maps directly to the identity of the enum. * For an array type, it maps to a tuple of enum identities. */ unsigned int _enumId : 12; /// Number of array dimensions int _dim : 7; public: /// Default constructor Type(void) : _ti(TI_PAR), _bt(BT_UNKNOWN), _st(ST_PLAIN), _ot(OT_PRESENT), _cv(CV_NO), _enumId(0), _dim(0) {} /// Access type-inst TypeInst ti(void) const { return static_cast(_ti); } /// Set type-inst void ti(const TypeInst& t) { _ti = t; if (t==TI_VAR) _cv=CV_YES; } /// Access basic type BaseType bt(void) const { return static_cast(_bt); } /// Set basic type void bt(const BaseType& b) { _bt = b; } /// Access set type SetType st(void) const { return static_cast(_st); } /// Set set type void st(const SetType& s) { _st = s; } /// Access opt type OptType ot(void) const { return static_cast(_ot); } /// Set opt type void ot(const OptType& o) { _ot = o; } /// Access var-in-par type bool cv(void) const { return static_cast(_cv) == CV_YES; } /// Set var-in-par type void cv(bool b) { _cv = b ? CV_YES : CV_NO; } /// Access enum identifier unsigned int enumId(void) const { return _enumId; } /// Set enum identifier void enumId(unsigned int eid) { _enumId = eid; } /// Access dimensions int dim(void) const { return _dim; } /// Set dimensions void dim(int d) { _dim = d; assert(_dim==d); } protected: /// Constructor Type(const TypeInst& ti, const BaseType& bt, const SetType& st, unsigned int enumId, int dim) : _ti(ti), _bt(bt), _st(st), _ot(OT_PRESENT), _cv(ti==TI_VAR ? CV_YES : CV_NO) , _enumId(enumId), _dim(dim) {} public: static Type parint(int dim=0) { return Type(TI_PAR,BT_INT,ST_PLAIN,0,dim); } static Type parenum(unsigned int enumId, int dim=0) { return Type(TI_PAR,BT_INT,ST_PLAIN,enumId,dim); } static Type parbool(int dim=0) { return Type(TI_PAR,BT_BOOL,ST_PLAIN,0,dim); } static Type parfloat(int dim=0) { return Type(TI_PAR,BT_FLOAT,ST_PLAIN,0,dim); } static Type parstring(int dim=0) { return Type(TI_PAR,BT_STRING,ST_PLAIN,0,dim); } static Type partop(int dim=0) { return Type(TI_PAR,BT_TOP,ST_PLAIN,0,dim); } static Type ann(int dim=0) { return Type(TI_PAR,BT_ANN,ST_PLAIN,0,dim); } static Type parsetint(int dim=0) { return Type(TI_PAR,BT_INT,ST_SET,0,dim); } static Type parsetenum(unsigned int enumId, int dim=0) { return Type(TI_PAR,BT_INT,ST_SET,enumId,dim); } static Type parsetbool(int dim=0) { return Type(TI_PAR,BT_BOOL,ST_SET,0,dim); } static Type parsetfloat(int dim=0) { return Type(TI_PAR,BT_FLOAT,ST_SET,0,dim); } static Type parsetstring(int dim=0) { return Type(TI_PAR,BT_STRING,ST_SET,0,dim); } static Type varint(int dim=0) { return Type(TI_VAR,BT_INT,ST_PLAIN,0,dim); } static Type varenumint(unsigned int enumId, int dim=0) { return Type(TI_VAR,BT_INT,ST_PLAIN,enumId,dim); } static Type varbool(int dim=0) { return Type(TI_VAR,BT_BOOL,ST_PLAIN,0,dim); } static Type varfloat(int dim=0) { return Type(TI_VAR,BT_FLOAT,ST_PLAIN,0,dim); } static Type varsetint(int dim=0) { return Type(TI_VAR,BT_INT,ST_SET,0,dim); } static Type varbot(int dim=0) { return Type(TI_VAR,BT_BOT,ST_PLAIN,0,dim); } static Type bot(int dim=0) { return Type(TI_PAR,BT_BOT,ST_PLAIN,0,dim); } static Type top(int dim=0) { return Type(TI_PAR,BT_TOP,ST_PLAIN,0,dim); } static Type vartop(int dim=0) { return Type(TI_VAR,BT_TOP,ST_PLAIN,0,dim); } static Type optvartop(int dim=0) { Type t(TI_VAR,BT_TOP,ST_PLAIN,0,dim); t._ot = OT_OPTIONAL; return t; } static Type optpartop(int dim=0) { Type t(TI_PAR,BT_TOP,ST_PLAIN,0,dim); t._ot = OT_OPTIONAL; return t; } static Type unboxedint; static Type unboxedfloat; bool isunknown(void) const { return _bt==BT_UNKNOWN; } bool isplain(void) const { return _dim==0 && _st==ST_PLAIN && _ot==OT_PRESENT; } bool isint(void) const { return _dim==0 && _st==ST_PLAIN && _bt==BT_INT; } bool isbot(void) const { return _bt==BT_BOT; } bool isfloat(void) const { return _dim==0 && _st==ST_PLAIN && _bt==BT_FLOAT; } bool isbool(void) const { return _dim==0 && _st==ST_PLAIN && _bt==BT_BOOL; } bool isstring(void) const { return isplain() && _bt==BT_STRING; } bool isvar(void) const { return _ti!=TI_PAR; } bool isvarbool(void) const { return _ti==TI_VAR && _dim==0 && _st==ST_PLAIN && _bt==BT_BOOL && _ot==OT_PRESENT; } bool isvarfloat(void) const { return _ti==TI_VAR && _dim==0 && _st==ST_PLAIN && _bt==BT_FLOAT && _ot==OT_PRESENT; } bool isvarint(void) const { return _ti==TI_VAR && _dim==0 && _st==ST_PLAIN && _bt==BT_INT && _ot==OT_PRESENT; } bool ispar(void) const { return _ti==TI_PAR; } bool isopt(void) const { return _ot==OT_OPTIONAL; } bool ispresent(void) const { return _ot==OT_PRESENT; } bool is_set(void) const { return _dim==0 && _st==ST_SET; } bool isintset(void) const { return is_set() && (_bt==BT_INT || _bt==BT_BOT); } bool isboolset(void) const { return is_set() && (_bt==BT_BOOL || _bt==BT_BOT); } bool isfloatset(void) const { return is_set() && (_bt==BT_FLOAT || _bt==BT_BOT); } bool isann(void) const { return isplain() && _bt==BT_ANN; } bool isintarray(void) const { return _dim==1 && _st==ST_PLAIN && _ot==OT_PRESENT && _bt==BT_INT; } bool isboolarray(void) const { return _dim==1 && _st==ST_PLAIN && _ot==OT_PRESENT && _bt==BT_BOOL; } bool isintsetarray(void) const { return _dim==1 && _st==ST_SET && _bt==BT_INT; } bool operator== (const Type& t) const { return _ti==t._ti && _bt==t._bt && _st==t._st && _ot==t._ot && _dim==t._dim; } bool operator!= (const Type& t) const { return !this->operator==(t); } // protected: int toInt(void) const { return + ((1-static_cast(_st))<<28) + (static_cast(_bt)<<24) + (static_cast(_ti)<<21) + (static_cast(_ot)<<20) + (static_cast(_enumId)<<8) + (_dim == -1 ? 1 : (_dim == 0 ? 0 : _dim+1)); } static Type fromInt(int i) { Type t; t._st = 1-static_cast((i >> 28) & 0x1); t._bt = static_cast((i >> 24) & 0xF); t._ti = static_cast((i >> 21) & 0x7); t._ot = static_cast((i >> 20) & 0x1); t._enumId = static_cast((i >> 8) & 0xFFF); int dim = (i & 0x7F); t._dim = (dim == 0 ? 0 : (dim==1 ? -1 : dim-1)); return t; } std::string toString(EnvI& env) const; std::string nonEnumToString(void) const; public: /// Check if \a bt0 is a subtype of \a bt1 static bool bt_subtype(const Type& t0, const Type& t1, bool strictEnums) { if (t0.bt() == t1.bt() && (!strictEnums || t0.dim() != 0 || (t0.enumId() == t1.enumId() || t1.enumId()==0))) return true; switch (t0.bt()) { case BT_BOOL: return (t1.bt()==BT_INT || t1.bt()==BT_FLOAT); case BT_INT: return t1.bt()==BT_FLOAT; default: return false; } } /// Check if this type is a subtype of \a t bool isSubtypeOf(const Type& t, bool strictEnums) const { if (_dim==0 && t._dim!=0 && _st==ST_SET && t._st==ST_PLAIN && ( bt()==BT_BOT || bt_subtype(*this, t, false) || t.bt()==BT_TOP) && _ti==TI_PAR && (_ot==OT_PRESENT || _ot==t._ot) ) return true; // either same dimension or t has variable dimension if (_dim!=t._dim && (_dim==0 || t._dim!=-1)) return false; // same type, this is present or both optional if (_ti==t._ti && bt_subtype(*this,t,strictEnums) && _st==t._st) return _ot==OT_PRESENT || _ot==t._ot; // this is par other than that same type as t if (_ti==TI_PAR && bt_subtype(*this,t,strictEnums) && _st==t._st) return _ot==OT_PRESENT || _ot==t._ot; if ( _ti==TI_PAR && t._bt==BT_BOT) return true; if ((_ti==t._ti || _ti==TI_PAR) && _bt==BT_BOT && (_st==t._st || _st==ST_PLAIN)) return _ot==OT_PRESENT || _ot==t._ot; if (t._bt==BT_TOP && (_ot==OT_PRESENT || _ot==t._ot) && (t._st==ST_PLAIN || _st==t._st) && (_ti==TI_PAR || t._ti==TI_VAR)) return true; return false; } /// Compare types int cmp(const Type& t) const { return toInt()t.toInt() ? 1 : 0); } }; }; #endif libminizinc-2.4.2/include/minizinc/typecheck.hh000066400000000000000000000054541360574160400216070ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_TYPECHECK_HH__ #define __MINIZINC_TYPECHECK_HH__ #include #include #include namespace MiniZinc { /// Scoped variable declarations class Scopes { protected: typedef IdMap DeclMap; struct Scope { /// Whether this scope is toplevel bool toplevel; /// Map from identifiers to declarations DeclMap m; /// Constructor Scope(void) : toplevel(false) {} }; /// Stack of scopes std::vector s; public: /// Constructor Scopes(void); /// Add a variable declaration void add(EnvI& env, VarDecl* vd); /// Push a new scope void push(bool toplevel); /// Pop topmost scope void pop(void); /// Return declaration for \a ident, or NULL if not found VarDecl* find(Id* ident); }; /// Topological sorting of items class TopoSorter { public: typedef std::vector Decls; typedef std::unordered_map PosMap; /// List of all declarations Decls decls; /// Scoped declarations Scopes scopes; /// Map from declarations to positions PosMap pos; /// The model Model* model; TopoSorter(Model* model0) : model(model0) {} /// Add a variable declaration item void add(EnvI& env, VarDeclI* vd, bool handleEnums, Model* enumItems); /// Get variable declaration from identifier \a id VarDecl* get(EnvI& env, const ASTString& id, const Location& loc); VarDecl* checkId(EnvI& env, const ASTString& ident, const Location& loc); VarDecl* checkId(EnvI& env, Id* ident, const Location& loc); /// Run the topological sorting for expression \a e void run(EnvI& env, Expression* e); }; /// Type check the model \a m void typecheck(Env& env, Model* m, std::vector& typeErrors, bool ignoreUndefinedParameters, bool allowMultiAssignment, bool isFlatZinc=false); /// Type check new assign item \a ai in model \a m void typecheck(Env& env, Model* m, AssignI* ai); /// Output description of parameters and output variables to \a os void output_model_interface(Env& env, Model* m, std::ostream& os, const std::vector& skipDirs); /// Output information about variable types (enum types) to \a os void output_model_variable_types(Env& env, Model* m, std::ostream& os, const std::vector& skipDirs); } #endif libminizinc-2.4.2/include/minizinc/utils.hh000066400000000000000000000135271360574160400207700ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_UTILS_H__ #define __MINIZINC_UTILS_H__ #include #include #include #include #include #include #include #include #include #include #include #ifdef MZN_HAS_LLROUND #include namespace MiniZinc { inline long long int round_to_longlong(double v) { return ::llround(v); } } #else namespace MiniZinc { inline long long int round_to_longlong(double v) { return static_cast(v < 0 ? v-0.5 : v+0.5); } } #endif namespace MiniZinc { // #define __MZN_PRINTATONCE__ #ifdef __MZN_PRINTATONCE__ #define __MZN_PRINT_SRCLOC(e1, e2) \ std::cerr << '\n' << __FILE__ << ": " << __LINE__ << " (" << __func__ \ << "): not " << e1 << ": " << std::flush; \ std::cerr << e2 << std::endl #else #define __MZN_PRINT_SRCLOC(e1, e2) #endif #define MZN_ASSERT_HARD( c ) \ do { if ( !(c) ) { __MZN_PRINT_SRCLOC( #c, "" ); throw InternalError( #c ); } } while (0) #define MZN_ASSERT_HARD_MSG( c, e ) \ do { if ( !(c) ) { __MZN_PRINT_SRCLOC( #c, e ); \ std::ostringstream oss; oss << "not " << #c << ": " << e; \ throw MiniZinc::InternalError( oss.str() ); } } while (0) inline bool beginswith(std::string s, std::string t) { return s.compare(0, t.length(), t)==0; } inline void checkIOStatus( bool fOk, std::string msg, bool fHard=1 ) { if ( !fOk ) { #ifdef _MSC_VER char errBuf[1024]; strerror_s(errBuf, sizeof(errBuf), errno); #else char* errBuf = strerror(errno); #endif std::cerr << "\n " << msg << ": " << errBuf << "." << std::endl; MZN_ASSERT_HARD_MSG ( !fHard, msg << ": " << errBuf ); } } template inline bool assignStr(T*, const std::string ) { return false; } template<> inline bool assignStr(std::string* pS, const std::string s ) { *pS = s; return true; } /// A simple per-cmdline option parser class CLOParser { int& i; // current item std::vector& argv; public: CLOParser( int& ii, std::vector& av ) : i(ii), argv(av) { } template inline bool get( const char* names, // space-separated option list Value* pResult=nullptr, // pointer to value storage bool fValueOptional=false // if pResult, for non-string values ) { return getOption( names, pResult, fValueOptional ); } template inline bool getOption( const char* names, // space-separated option list Value* pResult=nullptr, // pointer to value storage bool fValueOptional=false // if pResult, for non-string values ) { assert(0 == strchr(names, ',')); assert(0 == strchr(names, ';')); if( i>=argv.size() ) return false; std::string arg( argv[i] ); /// Separate keywords std::string keyword; std::istringstream iss( names ); while ( iss >> keyword ) { if ( ((2=argv.size() ) { --i; return fValueOptional; } arg = argv[i]; } assert( pResult ); if ( assignStr( pResult, arg ) ) return true; std::istringstream iss( arg ); Value tmp; if ( !( iss >> tmp ) ) { if (!combinedArg) --i; if ( fValueOptional ) { return true; } // Not print because another agent can handle this option // cerr << "\nBad value for " << keyword << ": " << arg << endl; return false; } *pResult = tmp; return true; } return false; } }; // class CLOParser /// This class prints a value if non-0 and adds comma if not 1st time class HadOne { bool fHadOne=false; public: template std::string operator()(const N& val, const char* descr=0) { std::ostringstream oss; if ( val ) { if ( fHadOne ) oss << ", "; fHadOne=true; oss << val; if ( descr ) oss << descr; } return oss.str(); } void reset() { fHadOne=false; } operator bool() const { return fHadOne; } bool operator!() const { return !fHadOne; } }; /// Split a string into words /// Add the words into the given vector inline void split(const std::string& str, std::vector& words) { std::istringstream iss(str); std::string buf; while (iss) { iss >> buf; words.push_back(buf); } } /// Puts the strings' c_str()s into the 2nd argument. /// The latter is only valid as long as the former isn't changed. inline void vecString2vecPChar(const std::vector& vS, std::vector& vPC) { vPC.resize(vS.size()); for ( size_t i=0; i */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_UTILS_SAVESTREAM_H__ #define __MINIZINC_UTILS_SAVESTREAM_H__ #include namespace MiniZinc { /// Helper class to redirect, e.g., stdout to stderr class StreamRedir { /// The stream to be changed FILE * const d_s0; /* * Structure for retaining information about a stream, sufficient to * recreate that stream later on. * See https://stackoverflow.com/questions/4760201/how-do-i-suppress-output-while-using-a-dynamic-library */ struct stream_info { int fd=-1; fpos_t pos; }; /// The original stream stream_info d_si; public: /// Constructs with the stream to be changed // StreamRedir(FILE* s0); /// Constructs with s0 and replaces it by s1 StreamRedir(FILE* s0, FILE* s1, bool fFlush=true); ~StreamRedir(); /// Restore original void restore(bool fFLush=true); protected: /// Replace & save stream by s1 void replaceStream(FILE* s1, bool fFlush=true); }; } #endif // __MINIZINC_UTILS_SAVESTREAM_H__ libminizinc-2.4.2/include/minizinc/values.hh000066400000000000000000000670041360574160400211260ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __MINIZINC_VALUES_HH__ #define __MINIZINC_VALUES_HH__ #include #include #include #include #include #include #include #include #ifdef min #undef min #endif #ifdef max #undef max #endif namespace MiniZinc { class IntVal; } namespace std { MiniZinc::IntVal abs(const MiniZinc::IntVal& x); } namespace MiniZinc { class FloatVal; class IntVal { friend IntVal operator +(const IntVal& x, const IntVal& y); friend IntVal operator -(const IntVal& x, const IntVal& y); friend IntVal operator *(const IntVal& x, const IntVal& y); friend IntVal operator /(const IntVal& x, const IntVal& y); friend IntVal operator %(const IntVal& x, const IntVal& y); friend IntVal std::abs(const MiniZinc::IntVal& x); friend bool operator ==(const IntVal& x, const IntVal& y); friend class FloatVal; private: long long int _v; bool _infinity; IntVal(long long int v, bool infinity) : _v(v), _infinity(infinity) {} static long long int safePlus(long long int x, long long int y) { if (x < 0) { if (y < std::numeric_limits::min() - x) throw ArithmeticError("integer overflow"); } else { if (y > std::numeric_limits::max() - x) throw ArithmeticError("integer overflow"); } return x+y; } static long long int safeMinus(long long int x, long long int y) { if (x < 0) { if (y > x - std::numeric_limits::min()) throw ArithmeticError("integer overflow"); } else { if (y < x - std::numeric_limits::max()) throw ArithmeticError("integer overflow"); } return x-y; } static long long int safeMult(long long int x, long long int y) { if (y==0) return 0; long long unsigned int x_abs = (x < 0 ? 0-x : x); long long unsigned int y_abs = (y < 0 ? 0-y : y); if (x_abs > std::numeric_limits::max() / y_abs) throw ArithmeticError("integer overflow"); return x*y; } static long long int safeDiv(long long int x, long long int y) { if (y==0) throw ArithmeticError("integer division by zero"); if (x==0) return 0; if (x==std::numeric_limits::min() && y==-1) throw ArithmeticError("integer overflow"); return x/y; } static long long int safeMod(long long int x, long long int y) { if (y==0) throw ArithmeticError("integer division by zero"); if (y==-1) return 0; return x%y; } public: IntVal(void) : _v(0), _infinity(false) {} IntVal(long long int v) : _v(v), _infinity(false) {} IntVal(const FloatVal& v); long long int toInt(void) const { if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value"); return _v; } bool isFinite(void) const { return !_infinity; } bool isPlusInfinity(void) const { return _infinity && _v==1; } bool isMinusInfinity(void) const { return _infinity && _v==-1; } IntVal& operator +=(const IntVal& x) { if (! (isFinite() && x.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); _v = safePlus(_v, x._v); return *this; } IntVal& operator -=(const IntVal& x) { if (! (isFinite() && x.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); _v = safeMinus(_v, x._v); return *this; } IntVal& operator *=(const IntVal& x) { if (! (isFinite() && x.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); _v = safeMult(_v, x._v); return *this; } IntVal& operator /=(const IntVal& x) { if (! (isFinite() && x.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); _v = safeDiv(_v, x._v); return *this; } IntVal operator -() const { IntVal r = *this; r._v = safeMinus(0, _v); return r; } IntVal& operator ++() { if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value"); _v = safePlus(_v,1); return *this; } IntVal operator ++(int) { if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value"); IntVal ret = *this; _v = safePlus(_v,1); return ret; } IntVal& operator --() { if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value"); _v = safeMinus(_v,1); return *this; } IntVal operator --(int) { if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value"); IntVal ret = *this; _v = safeMinus(_v,1); return ret; } IntVal pow(const IntVal& exponent) { if (!exponent.isFinite() || !isFinite()) throw ArithmeticError("arithmetic operation on infinite value"); if (exponent==0) return 1; if (exponent==1) return *this; IntVal result = 1; for (int i=0; i longhash; return longhash(_v); } }; inline bool operator ==(const IntVal& x, const IntVal& y) { return x._infinity==y._infinity && x._v == y._v; } inline bool operator <=(const IntVal& x, const IntVal& y) { return y.isPlusInfinity() || x.isMinusInfinity() || (x.isFinite() && y.isFinite() && x.toInt() <= y.toInt()); } inline bool operator <(const IntVal& x, const IntVal& y) { return (y.isPlusInfinity() && !x.isPlusInfinity()) || (x.isMinusInfinity() && !y.isMinusInfinity()) || (x.isFinite() && y.isFinite() && x.toInt() < y.toInt()); } inline bool operator >=(const IntVal& x, const IntVal& y) { return y <= x; } inline bool operator >(const IntVal& x, const IntVal& y) { return y < x; } inline bool operator !=(const IntVal& x, const IntVal& y) { return !(x==y); } inline IntVal operator +(const IntVal& x, const IntVal& y) { if (! (x.isFinite() && y.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); return IntVal::safePlus(x._v,y._v); } inline IntVal operator -(const IntVal& x, const IntVal& y) { if (! (x.isFinite() && y.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); return IntVal::safeMinus(x._v,y._v); } inline IntVal operator *(const IntVal& x, const IntVal& y) { if (!x.isFinite()) { if (y.isFinite() && (y._v==1 || y._v==-1)) return IntVal(IntVal::safeMult(x._v,y._v),!x.isFinite()); } else if (!y.isFinite()) { if (x.isFinite() && (y._v==1 || y._v==-1)) return IntVal(IntVal::safeMult(x._v,y._v),true); } else { return IntVal::safeMult(x._v,y._v); } throw ArithmeticError("arithmetic operation on infinite value"); } inline IntVal operator /(const IntVal& x, const IntVal& y) { if (y.isFinite() && (y._v==1 || y._v==-1)) return IntVal(IntVal::safeMult(x._v,y._v), !x.isFinite()); if (! (x.isFinite() && y.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); return IntVal::safeDiv(x._v,y._v); } inline IntVal operator %(const IntVal& x, const IntVal& y) { if (! (x.isFinite() && y.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); return IntVal::safeMod(x._v,y._v); } template std::basic_ostream& operator <<(std::basic_ostream& os, const IntVal& s) { if (s.isMinusInfinity()) return os << "-infinity"; else if (s.isPlusInfinity()) return os << "infinity"; else return os << s.toInt(); } } namespace std { inline MiniZinc::IntVal abs(const MiniZinc::IntVal& x) { if (!x.isFinite()) return MiniZinc::IntVal::infinity(); return x < 0 ? MiniZinc::IntVal::safeMinus(0,x._v) : x; } inline MiniZinc::IntVal min(const MiniZinc::IntVal& x, const MiniZinc::IntVal& y) { return x <= y ? x : y; } inline MiniZinc::IntVal max(const MiniZinc::IntVal& x, const MiniZinc::IntVal& y) { return x >= y ? x : y; } template<> struct equal_to { public: bool operator()(const MiniZinc::IntVal& s0, const MiniZinc::IntVal& s1) const { return s0==s1; } }; inline MiniZinc::FloatVal abs(const MiniZinc::FloatVal&); } namespace std { template<> struct hash { public: size_t operator()(const MiniZinc::IntVal& s) const { return s.hash(); } }; } namespace MiniZinc { class FloatVal { friend FloatVal operator +(const FloatVal& x, const FloatVal& y); friend FloatVal operator -(const FloatVal& x, const FloatVal& y); friend FloatVal operator *(const FloatVal& x, const FloatVal& y); friend FloatVal operator /(const FloatVal& x, const FloatVal& y); friend FloatVal std::abs(const MiniZinc::FloatVal& x); friend bool operator ==(const FloatVal& x, const FloatVal& y); friend class IntVal; private: double _v; bool _infinity; void checkOverflow(void) { if (!std::isfinite(_v)) throw ArithmeticError("overflow in floating point operation"); } FloatVal(double v, bool infinity) : _v(v), _infinity(infinity) { checkOverflow(); } public: FloatVal(void) : _v(0.0), _infinity(false) {} FloatVal(double v) : _v(v), _infinity(false) { checkOverflow(); } FloatVal(const IntVal& v) : _v(static_cast(v._v)), _infinity(!v.isFinite()) {} double toDouble(void) const { if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value"); return _v; } bool isFinite(void) const { return !_infinity; } bool isPlusInfinity(void) const { return _infinity && _v==1.0; } bool isMinusInfinity(void) const { return _infinity && _v==-1.0; } FloatVal& operator +=(const FloatVal& x) { if (! (isFinite() && x.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); _v += x._v; checkOverflow(); return *this; } FloatVal& operator -=(const FloatVal& x) { if (! (isFinite() && x.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); _v -= x._v; checkOverflow(); return *this; } FloatVal& operator *=(const FloatVal& x) { if (! (isFinite() && x.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); _v *= x._v; checkOverflow(); return *this; } FloatVal& operator /=(const FloatVal& x) { if (! (isFinite() && x.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); _v = _v / x._v; checkOverflow(); return *this; } FloatVal operator -() const { FloatVal r = *this; r._v = -r._v; return r; } FloatVal& operator ++() { if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value"); _v = _v + 1; checkOverflow(); return *this; } FloatVal operator ++(int) { if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value"); FloatVal ret = *this; _v = _v + 1; checkOverflow(); return ret; } FloatVal& operator --() { if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value"); _v = _v - 1; checkOverflow(); return *this; } FloatVal operator --(int) { if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value"); FloatVal ret = *this; _v = _v - 1; checkOverflow(); return ret; } static const FloatVal infinity(void); /// Infinity-safe addition FloatVal plus(int x) { if (isFinite()) return (*this)+x; else return *this; } /// Infinity-safe subtraction FloatVal minus(int x) { if (isFinite()) return (*this)-x; else return *this; } size_t hash(void) const { std::hash doublehash; return doublehash(_v); } }; inline bool operator ==(const FloatVal& x, const FloatVal& y) { return x._infinity==y._infinity && x._v == y._v; } inline bool operator <=(const FloatVal& x, const FloatVal& y) { return y.isPlusInfinity() || x.isMinusInfinity() || (x.isFinite() && y.isFinite() && x.toDouble() <= y.toDouble()); } inline bool operator <(const FloatVal& x, const FloatVal& y) { return (y.isPlusInfinity() && !x.isPlusInfinity()) || (x.isMinusInfinity() && !y.isMinusInfinity()) || (x.isFinite() && y.isFinite() && x.toDouble() < y.toDouble()); } inline bool operator >=(const FloatVal& x, const FloatVal& y) { return y <= x; } inline bool operator >(const FloatVal& x, const FloatVal& y) { return y < x; } inline bool operator !=(const FloatVal& x, const FloatVal& y) { return !(x==y); } inline FloatVal operator +(const FloatVal& x, const FloatVal& y) { if (! (x.isFinite() && y.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); return x.toDouble()+y.toDouble(); } inline FloatVal operator -(const FloatVal& x, const FloatVal& y) { if (! (x.isFinite() && y.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); return x.toDouble()-y.toDouble(); } inline FloatVal operator *(const FloatVal& x, const FloatVal& y) { if (! (x.isFinite() && y.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); return x.toDouble()*y.toDouble(); } inline FloatVal operator /(const FloatVal& x, const FloatVal& y) { if (! (x.isFinite() && y.isFinite())) throw ArithmeticError("arithmetic operation on infinite value"); return x.toDouble()/y.toDouble(); } template std::basic_ostream& operator <<(std::basic_ostream& os, const FloatVal& s) { if (s.isMinusInfinity()) return os << "-infinity"; else if (s.isPlusInfinity()) return os << "infinity"; else return os << s.toDouble(); } inline IntVal::IntVal(const FloatVal& v) : _v(static_cast(v._v)), _infinity(!v.isFinite()) {} } namespace std { inline MiniZinc::FloatVal abs(const MiniZinc::FloatVal& x) { if (!x.isFinite()) return MiniZinc::FloatVal::infinity(); return x.toDouble() < 0 ? MiniZinc::FloatVal(-x.toDouble()) : x; } inline MiniZinc::FloatVal min(const MiniZinc::FloatVal& x, const MiniZinc::FloatVal& y) { return x <= y ? x : y; } inline MiniZinc::FloatVal max(const MiniZinc::FloatVal& x, const MiniZinc::FloatVal& y) { return x >= y ? x : y; } inline MiniZinc::FloatVal floor(const MiniZinc::FloatVal& x) { if (!x.isFinite()) return x; return floor(x.toDouble()); } inline MiniZinc::FloatVal ceil(const MiniZinc::FloatVal& x) { if (!x.isFinite()) return x; return ceil(x.toDouble()); } template<> struct equal_to { public: bool operator()(const MiniZinc::FloatVal& s0, const MiniZinc::FloatVal& s1) const { return s0==s1; } }; } namespace std { template<> struct hash { public: size_t operator()(const MiniZinc::FloatVal& s) const { return s.hash(); } }; } namespace MiniZinc { typedef unsigned long long int UIntVal; /// An integer set value class IntSetVal : public ASTChunk { public: /// Contiguous range struct Range { /// Range minimum IntVal min; /// Range maximum IntVal max; /// Construct range from \a m to \a n Range(IntVal m, IntVal n) : min(m), max(n) {} /// Default constructor Range(void) {} }; private: /// Return range at position \a i Range& get(int i) { return reinterpret_cast(_data)[i]; } /// Return range at position \a i const Range& get(int i) const { return reinterpret_cast(_data)[i]; } /// Construct empty set IntSetVal(void) : ASTChunk(0) {} /// Construct set of single range IntSetVal(IntVal m, IntVal n); /// Construct set from \a s IntSetVal(const std::vector& s) : ASTChunk(sizeof(Range)*s.size()) { for (unsigned int i=static_cast(s.size()); i--;) get(i) = s[i]; } /// Disabled IntSetVal(const IntSetVal& r); /// Disabled IntSetVal& operator =(const IntSetVal& r); public: /// Return number of ranges int size(void) const { return static_cast(_size / sizeof(Range)); } /// Return minimum, or infinity if set is empty IntVal min(void) const { return size()==0 ? IntVal::infinity() : get(0).min; } /// Return maximum, or minus infinity if set is empty IntVal max(void) const { return size()==0 ? -IntVal::infinity() : get(size()-1).max; } /// Return minimum of range \a i IntVal min(int i) const { assert(i(ASTChunk::alloc(0)); new (r) IntSetVal(); return r; } /// Allocate set \f$\{m,n\}\f$ from context static IntSetVal* a(IntVal m, IntVal n) { if (m>n) { return a(); } else { IntSetVal* r = static_cast(ASTChunk::alloc(sizeof(Range))); new (r) IntSetVal(m,n); return r; } } /// Allocate set using iterator \a i template static IntSetVal* ai(I& i) { std::vector s; for (; i(); ++i) s.push_back(Range(i.min(),i.max())); IntSetVal* r = static_cast( ASTChunk::alloc(sizeof(Range)*s.size())); new (r) IntSetVal(s); return r; } /// Allocate set from vector \a s0 (may contain duplicates) static IntSetVal* a(const std::vector& s0) { if (s0.size()==0) return a(); std::vector s=s0; std::sort(s.begin(),s.end()); std::vector ranges; IntVal min=s[0]; IntVal max=min; for (unsigned int i=1; imax+1) { ranges.push_back(Range(min,max)); min=s[i]; max=min; } else { max=s[i]; } } ranges.push_back(Range(min,max)); IntSetVal* r = static_cast( ASTChunk::alloc(sizeof(Range)*ranges.size())); new (r) IntSetVal(ranges); return r; } static IntSetVal* a(const std::vector& ranges) { IntSetVal* r = static_cast(ASTChunk::alloc(sizeof(Range)*ranges.size())); new (r) IntSetVal(ranges); return r; } /// Check if set contains \a v bool contains(const IntVal& v) { for (int i=0; isize()) return false; for (int i=0; imin(i) || max(i)!=s->max(i)) return false; return true; } /// Mark for garbage collection void mark(void) { _gc_mark = 1; } }; /// Iterator over an IntSetVal class IntSetRanges { /// The set value const IntSetVal* rs; /// The current range int n; public: /// Constructor IntSetRanges(const IntSetVal* r) : rs(r), n(0) {} /// Check if iterator is still valid bool operator()(void) const { return nsize(); } /// Move to next range void operator++(void) { ++n; } /// Return minimum of current range IntVal min(void) const { return rs->min(n); } /// Return maximum of current range IntVal max(void) const { return rs->max(n); } /// Return width of current range IntVal width(void) const { return rs->width(n); } }; template std::basic_ostream& operator <<(std::basic_ostream& os, const IntSetVal& s) { if (s.size()==0) { os << "1..0"; } else if(s.size() == 1) { // Print the range IntSetRanges isr(&s); os << isr.min() << ".." << isr.max(); } else { // Print each element of the set bool first = true; os << "{"; for (IntSetRanges isr(&s); isr(); ++isr) { if(!first) os << ", "; first = false; for(IntVal v = isr.min(); v < isr.max(); ++v) { os << v; } } os << "}"; } return os; } /// An integer set value class FloatSetVal : public ASTChunk { public: /// Contiguous range struct Range { /// Range minimum FloatVal min; /// Range maximum FloatVal max; /// Construct range from \a m to \a n Range(FloatVal m, FloatVal n) : min(m), max(n) {} /// Default constructor Range(void) {} }; private: /// Return range at position \a i Range& get(int i) { return reinterpret_cast(_data)[i]; } /// Return range at position \a i const Range& get(int i) const { return reinterpret_cast(_data)[i]; } /// Construct empty set FloatSetVal(void) : ASTChunk(0) {} /// Construct set of single range FloatSetVal(FloatVal m, FloatVal n); /// Construct set from \a s FloatSetVal(const std::vector& s) : ASTChunk(sizeof(Range)*s.size()) { for (unsigned int i=static_cast(s.size()); i--;) get(i) = s[i]; } /// Disabled FloatSetVal(const FloatSetVal& r); /// Disabled FloatSetVal& operator =(const FloatSetVal& r); public: /// Return number of ranges int size(void) const { return static_cast(_size / sizeof(Range)); } /// Return minimum, or infinity if set is empty FloatVal min(void) const { return size()==0 ? FloatVal::infinity() : get(0).min; } /// Return maximum, or minus infinity if set is empty FloatVal max(void) const { return size()==0 ? -FloatVal::infinity() : get(size()-1).max; } /// Return minimum of range \a i FloatVal min(int i) const { assert(i(ASTChunk::alloc(0)); new (r) FloatSetVal(); return r; } /// Allocate set \f$\{m,n\}\f$ from context static FloatSetVal* a(FloatVal m, FloatVal n) { if (m>n) { return a(); } else { FloatSetVal* r = static_cast(ASTChunk::alloc(sizeof(Range))); new (r) FloatSetVal(m,n); return r; } } /// Allocate set using iterator \a i template static FloatSetVal* ai(I& i) { std::vector s; for (; i(); ++i) s.push_back(Range(i.min(),i.max())); FloatSetVal* r = static_cast(ASTChunk::alloc(sizeof(Range)*s.size())); new (r) FloatSetVal(s); return r; } /// Allocate set from vector \a s0 (may contain duplicates) static FloatSetVal* a(const std::vector& s0) { if (s0.size()==0) return a(); std::vector s=s0; std::sort(s.begin(),s.end()); std::vector ranges; FloatVal min=s[0]; FloatVal max=min; for (unsigned int i=1; imax) { ranges.push_back(Range(min,max)); min=s[i]; max=min; } else { max=s[i]; } } ranges.push_back(Range(min,max)); FloatSetVal* r = static_cast(ASTChunk::alloc(sizeof(Range)*ranges.size())); new (r) FloatSetVal(ranges); return r; } static FloatSetVal* a(const std::vector& ranges) { FloatSetVal* r = static_cast(ASTChunk::alloc(sizeof(Range)*ranges.size())); new (r) FloatSetVal(ranges); return r; } /// Check if set contains \a v bool contains(const FloatVal& v) { for (int i=0; isize()) return false; for (int i=0; imin(i) || max(i)!=s->max(i)) return false; return true; } /// Mark for garbage collection void mark(void) { _gc_mark = 1; } }; /// Iterator over an IntSetVal class FloatSetRanges { /// The set value const FloatSetVal* rs; /// The current range int n; public: /// Constructor FloatSetRanges(const FloatSetVal* r) : rs(r), n(0) {} /// Check if iterator is still valid bool operator()(void) const { return nsize(); } /// Move to next range void operator++(void) { ++n; } /// Return minimum of current range FloatVal min(void) const { return rs->min(n); } /// Return maximum of current range FloatVal max(void) const { return rs->max(n); } /// Return width of current range FloatVal width(void) const { return rs->width(n); } }; template std::basic_ostream& operator <<(std::basic_ostream& os, const FloatSetVal& s) { for (FloatSetRanges isr(&s); isr(); ++isr) os << isr.min() << ".." << isr.max() << " "; return os; } } #endif libminizinc-2.4.2/lib/000077500000000000000000000000001360574160400146025ustar00rootroot00000000000000libminizinc-2.4.2/lib/MIPdomains.cpp000066400000000000000000002673701360574160400173250ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was ! distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #undef ERROR // MICROsoft. #undef min #undef max #endif #include #include #include #include #include #include #include #include // temporary #include //#include #include #include #include /// TODOs /// TODO Not going to work for float vars because of round-offs in the domain interval sorting... /// set_in etc. are ! propagated between views /// CLEANUP after work: ~destructor /// Also check initexpr of all vars? DONE /// In case of only_range_domains we'd need to register inequalities /// - so better turn that off TODO /// CSE for lineq coefs TODO /// TODO use integer division instead of INT_EPS #define INT_EPS 1e-5 // the absolute epsilon for integrality of integer vars. #define __MZN__MIPDOMAINS__PRINTMORESTATS #define MZN_DBG_CHECK_ITER_CUTOUT // #define __MZN__DBGOUT__MIPDOMAINS__ #ifdef __MZN__DBGOUT__MIPDOMAINS__ #define DBGOUT_MIPD(s) std::cerr << s << std::endl #define DBGOUT_MIPD__(s) std::cerr << s << std::flush #define DBGOUT_MIPD_SELF(op) op #else #define DBGOUT_MIPD(s) do { } while ( false ) #define DBGOUT_MIPD__(s) do { } while ( false ) #define DBGOUT_MIPD_SELF(op) do { } while ( false ) #endif namespace MiniZinc { enum EnumStatIdx__MIPD { N_POSTs__all, // N all POSTs in the model N_POSTs__intCmpReif, N_POSTs__floatCmpReif, // in detail N_POSTs__intNE, N_POSTs__floatNE, N_POSTs__setIn, N_POSTs__domain, N_POSTs__setInReif, N_POSTs__eq_encode, N_POSTs__intAux, N_POSTs__floatAux, // Kind of equality connections between involved variables N_POSTs__eq2intlineq, N_POSTs__eq2floatlineq, N_POSTs__int2float, N_POSTs__internalvarredef, N_POSTs__initexpr1id, N_POSTs__initexpr1linexp, N_POSTs__initexprN, N_POSTs__eqNlineq, N_POSTs__eqNmapsize, // other N_POSTs__varsDirect, N_POSTs__varsInvolved, N_POSTs__NSubintvMin, N_POSTs__NSubintvSum, N_POSTs__NSubintvMax, // as N subintervals N_POSTs__SubSizeMin, N_POSTs__SubSizeSum, N_POSTs__SubSizeMax, // subintv. size N_POSTs__linCoefMin, N_POSTs__linCoefMax, N_POSTs__cliquesWithEqEncode, N_POSTs__clEEEnforced, N_POSTs__clEEFound, N_POSTs__size }; extern std::vector MIPD__stats; enum EnumReifType { RIT_None, RIT_Static, RIT_Reif, RIT_Halfreif }; enum EnumConstrType { CT_None, CT_Comparison, CT_SetIn, CT_Encode }; enum EnumCmpType { CMPT_None=0, CMPT_LE=-4, CMPT_GE=4, CMPT_EQ=1, CMPT_NE=3, CMPT_LT=-5, CMPT_GT=5, CMPT_LE_0=-6, CMPT_GE_0=6, CMPT_EQ_0=2, CMPT_LT_0=-7, CMPT_GT_0=7 }; enum EnumVarType { VT_None, VT_Int, VT_Float }; /// struct DomainCallType describes & characterizes a possible domain constr call struct DCT { const char* sFuncName=0; const std::vector& aParams; // unsigned iItem; // call's item number in the flat EnumReifType nReifType = RIT_None; // 0/static/halfreif/reif EnumConstrType nConstrType = CT_None; // EnumCmpType nCmpType = CMPT_None; EnumVarType nVarType = VT_None; FunctionI* &pfi; // double dEps = -1.0; DCT(const char* fn, const std::vector& prm, EnumReifType er, EnumConstrType ec, EnumCmpType ecmp, EnumVarType ev, FunctionI* &pfi__ ) : sFuncName(fn), aParams(prm), nReifType(er), nConstrType(ec), nCmpType(ecmp), nVarType(ev), pfi(pfi__) { } }; template struct Interval { N left = infMinus(), right = infPlus(); mutable VarDecl* varFlag=0; /*constexpr*/ static N infMinus() { return ( std::numeric_limits::has_infinity ) ? -std::numeric_limits::infinity() : std::numeric_limits::lowest(); } /*constexpr*/ static N infPlus() { return ( std::numeric_limits::has_infinity ) ? std::numeric_limits::infinity() : std::numeric_limits::max(); } Interval(N a=infMinus(), N b=infPlus()) : left(a), right(b) { } bool operator<( const Interval& intv ) const { if ( left < intv.left ) { // assert( right <= intv.left ); // assume disjoint return true; } return false; } }; typedef Interval IntvReal; template std::ostream& operator<< (std::ostream& os, const Interval& ii) { os << "[ " << ii.left << ", " << ii.right << " ] "; return os; } template class SetOfIntervals : public std::multiset > { public: using Intv = Interval; typedef std::multiset > Base; typedef typename Base::iterator iterator; SetOfIntervals() : Base() { } SetOfIntervals(std::initializer_list > il) : Base( il ) { } template SetOfIntervals( Iter i1, Iter i2 ) : Base( i1, i2 ) { } /// Number of integer values in all the intervals /// Assumes the interval bounds are ints int card_int() const; /// Max interval length N max_interval() const; /// Special insert function: check if interval is ok iterator insert(const Interval& iv) { if (iv.left > iv.right) { DBGOUT_MIPD( "Interval " << iv.left << ".." << iv.right << " is empty, difference: " << (iv.right-iv.left) << ". Skipping" ); return Base::end(); } return Base::insert(iv); } template void intersect(const SetOfIntervals& s2); /// Assumes open intervals to cut out from closed template void cutDeltas( const SetOfIntervals& s2, N1 delta ); template void cutDeltas(N1 left, N1 right, N1 delta) { SetOfIntervals soi; soi.insert(Interval(left, right)); cutDeltas(soi, delta); } /// Cut out an open interval from a set of closed ones (except for infinities) void cutOut(const Interval& intv); typedef std::pair SplitResult; SplitResult split(iterator& it, N pos); bool checkFiniteBounds(); /// Check there are no useless interval splittings bool checkDisjunctStrict(); Interval getBounds() const; /// Split domain into the integer values /// May assume integer bounds void split2Bits(); }; // class SetOfIntervals typedef SetOfIntervals SetOfIntvReal; template std::ostream& operator<< (std::ostream& os, const SetOfIntervals& soi) { os << "[[ "; for ( auto& ii : soi ) { os << "[ " << ii.left << ", " << ii.right; if ( ii.varFlag ) os << " @" << ii.varFlag; os << " ] "; } os << "]]"; return os; } template class LinEq__ { public: Coefs coefs; Vars vd; double rhs; }; template static std::ostream& operator<<( std::ostream& os, LinEq__& led ) { os << "( ["; for (auto c : led.coefs) os << c << ' '; os << " ] * [ "; for (auto v : led.vd) os << v->id()->str() << ' '; os <<" ] ) == " << led.rhs; return os; } typedef LinEq__, std::array > LinEq2Vars; typedef LinEq__, std::vector > LinEq; // struct LinEq2Vars { // std::array coefs; // std::array vd = { { 0, 0 } }; // double rhs; // }; // // struct LinEq { // std::vector coefs; // std::vector vd; // double rhs; // }; std::vector MIPD__stats( N_POSTs__size ); template static std::vector make_vec(T t1, T t2) { T c_array[] = { t1, t2 }; std::vector result(c_array, c_array + sizeof(c_array) / sizeof(c_array[0])); return result; } template static std::vector make_vec(T t1, T t2, T t3) { T c_array[] = { t1, t2, t3 }; std::vector result(c_array, c_array + sizeof(c_array) / sizeof(c_array[0])); return result; } template static std::vector make_vec(T t1, T t2, T t3, T t4) { T c_array[] = { t1, t2, t3, t4 }; std::vector result(c_array, c_array + sizeof(c_array) / sizeof(c_array[0])); return result; } class MIPD { public: MIPD(Env* env, bool fV, int nmi, double dmd) : nMaxIntv2Bits(nmi), dMaxNValueDensity(dmd), __env(env) { getEnv(); fVerbose=fV; } static bool fVerbose; const int nMaxIntv2Bits=0; // Maximal interval length to enforce equality encoding const double dMaxNValueDensity=3.0; // Maximal ratio card_int() / size() of a domain // to enforce ee bool MIPdomains() { MIPD__stats[ N_POSTs__NSubintvMin ] = 1e100; MIPD__stats[ N_POSTs__SubSizeMin ] = 1e100; if (!registerLinearConstraintDecls()) return true; if (!register__POSTconstraintDecls()) // not declared => no conversions return true; register__POSTvariables(); if ( vVarDescr.empty() ) return true; constructVarViewCliques(); if ( !decomposeDomains() ) return false; if ( fVerbose ) printStats(std::cerr); return true; } private: Env* __env=0; Env* getEnv() { MZN_MIPD__assert_hard(__env); return __env; } typedef VarDecl* PVarDecl; FunctionI *int_lin_eq; FunctionI *int_lin_le; FunctionI *float_lin_eq; FunctionI *float_lin_le; FunctionI *int2float; FunctionI *lin_exp_int; FunctionI *lin_exp_float; std::vector int_lin_eq_t = make_vec(Type::parint(1), Type::varint(1), Type::parint()); std::vector float_lin_eq_t = make_vec(Type::parfloat(1), Type::varfloat(1), Type::parfloat()); std::vector t_VIVF = make_vec( Type::varint(), Type::varfloat() ); // double float_lt_EPS_coef__ = 1e-5; bool registerLinearConstraintDecls() { EnvI& env = getEnv()->envi(); GCLock lock; int_lin_eq = env.model->matchFn(env, constants().ids.int_.lin_eq, int_lin_eq_t, false); DBGOUT_MIPD ( " int_lin_eq = " << int_lin_eq ); // MZN_MIPD__assert_hard(fi); // int_lin_eq = (fi && fi->e()) ? fi : NULL; int_lin_le = env.model->matchFn(env, constants().ids.int_.lin_le, int_lin_eq_t, false); float_lin_eq = env.model->matchFn(env, constants().ids.float_.lin_eq, float_lin_eq_t, false); float_lin_le = env.model->matchFn(env, constants().ids.float_.lin_le, float_lin_eq_t, false); int2float = env.model->matchFn(env, constants().ids.int2float, t_VIVF, false); lin_exp_int = env.model->matchFn(env, constants().ids.lin_exp, int_lin_eq_t, false); lin_exp_float = env.model->matchFn(env, constants().ids.lin_exp, float_lin_eq_t, false); if ( !(int_lin_eq&&int_lin_le&&float_lin_eq&&float_lin_le) ) { // say something... return false; } return true; // std::cerr << " lin_exp_int=" << lin_exp_int << std::endl; // std::cerr << " lin_exp_float=" << lin_exp_float << std::endl; // For this to work, need to define a function, see mzn_only_range_domains() // { // GCLock lock; // Call* call_EPS_for_LT = // new Call(Location(),"mzn_float_lt_EPS_coef__", std::vector()); // call_EPS_for_LT->type(Type::parfloat()); // call_EPS_for_LT->decl(env.model->matchFn(getEnv()->envi(), call_EPS_for_LT)); // float_lt_EPS_coef__ = eval_float(getEnv()->envi(), call_EPS_for_LT); // } } // bool matchAndMarkFunction(); // std::set funcs; /// Possible function param sets std::vector t_VII = make_vec( Type::varint(), Type::parint() ); std::vector t_VIVI = make_vec(Type::varint(), Type::varint()); std::vector t_VIIVI = make_vec(Type::varint(), Type::parint(), Type::varint()); std::vector t_VFVI = make_vec(Type::varfloat(), Type::varint()); std::vector t_VFVF = make_vec(Type::varfloat(), Type::varfloat()); std::vector t_VFFVI = make_vec(Type::varfloat(), Type::parfloat(), Type::varint()); std::vector t_VFFVIF = make_vec(Type::varfloat(), Type::parfloat(), Type::varint(), Type::parfloat() ); std::vector t_VFVIF = make_vec(Type::varfloat(), Type::varint(), Type::parfloat()); std::vector t_VFVIVF = make_vec(Type::varfloat(), Type::varint(), Type::varfloat()); std::vector t_VFVIVFF = make_vec(Type::varfloat(), Type::varint(), Type::varfloat(), Type::parfloat() ); std::vector t_VFVFF = make_vec(Type::varfloat(), Type::varfloat(), Type::parfloat()); std::vector t_VFFF = make_vec(Type::varfloat(), Type::parfloat(), Type::parfloat()); // std::vector t_VFVFVIF({ Type::varfloat(), Type::varfloat(), Type::varint(), Type::parfloat() }); std::vector t_VIAVI = make_vec(Type::varint(), Type::varint(1)); std::vector t_VISI = make_vec(Type::varint(), Type::parsetint()); std::vector t_VISIVI = make_vec(Type::varint(), Type::parsetint(), Type::varint()); // std::vector t_intarray(1); // t_intarray[0] = Type::parint(-1); typedef std::unordered_map M__POSTCallTypes; M__POSTCallTypes mCallTypes; // actually declared in the input std::vector aCT; // all possible // Fails: // DomainCallType a = { NULL, t_VII, RIT_Halfreif, CT_Comparison, CMPT_EQ, VT_Float }; /// struct VarDescr stores some info about variables involved in domain constr struct VarDescr { typedef unsigned char boolShort; VarDescr(VarDecl* vd_, boolShort fi, double l_=0.0, double u_=0.0) : lb(l_), ub(u_), vd(vd_), fInt(fi) { } double lb, ub; VarDecl* vd = 0; int nClique = -1; // clique number // std::vector aCalls; std::vector aCalls; boolShort fInt=0; ConstraintI* pEqEncoding=0; boolShort fDomainConstrProcessed=0; // boolShort fPropagatedViews=0; // boolShort fPropagatedLargerEqns=0; }; std::vector vVarDescr; FunctionI *int_le_reif__POST=0, *int_ge_reif__POST=0, *int_eq_reif__POST=0, *int_ne__POST=0, *float_le_reif__POST=0, *float_ge_reif__POST=0, *aux_float_lt_zero_iff_1__POST=0, *float_eq_reif__POST=0, *float_ne__POST=0, *aux_float_eq_zero_if_1__POST=0, *aux_int_le_zero_if_1__POST=0, *aux_float_le_zero_if_1__POST=0, *aux_float_lt_zero_if_1__POST=0, *equality_encoding__POST=0, *set_in__POST=0, *set_in_reif__POST=0; bool register__POSTconstraintDecls() { EnvI& env = getEnv()->envi(); GCLock lock; aCT.clear(); aCT.push_back(DCT("int_le_reif__POST", t_VIIVI, RIT_Reif, CT_Comparison, CMPT_LE, VT_Int, int_le_reif__POST)); aCT.push_back(DCT("int_ge_reif__POST", t_VIIVI, RIT_Reif, CT_Comparison, CMPT_GE, VT_Int, int_ge_reif__POST)); aCT.push_back(DCT("int_eq_reif__POST", t_VIIVI, RIT_Reif, CT_Comparison, CMPT_EQ, VT_Int, int_eq_reif__POST)); aCT.push_back(DCT("int_ne__POST", t_VII, RIT_Static, CT_Comparison, CMPT_NE, VT_Int, int_ne__POST)); aCT.push_back(DCT("float_le_reif__POST", t_VFFVIF, RIT_Reif, CT_Comparison, CMPT_LE, VT_Float, float_le_reif__POST)); aCT.push_back(DCT("float_ge_reif__POST", t_VFFVIF, RIT_Reif, CT_Comparison, CMPT_GE, VT_Float, float_ge_reif__POST)); aCT.push_back(DCT("aux_float_lt_zero_iff_1__POST", t_VFVIF, RIT_Reif, CT_Comparison, CMPT_LT, VT_Float, aux_float_lt_zero_iff_1__POST)); aCT.push_back(DCT("float_eq_reif__POST", t_VFFVIF, RIT_Reif, CT_Comparison, CMPT_EQ, VT_Float, float_eq_reif__POST)); aCT.push_back(DCT("float_ne__POST", t_VFFF, RIT_Static, CT_Comparison, CMPT_NE, VT_Float, float_ne__POST)); aCT.push_back(DCT("aux_float_eq_zero_if_1__POST", t_VFVIVF, RIT_Halfreif, CT_Comparison, CMPT_EQ_0, VT_Float, aux_float_eq_zero_if_1__POST)); aCT.push_back(DCT("aux_int_le_zero_if_1__POST", t_VIVI, RIT_Halfreif, CT_Comparison, CMPT_LE_0, VT_Int, aux_int_le_zero_if_1__POST)); aCT.push_back(DCT("aux_float_le_zero_if_1__POST", t_VFVIVF, RIT_Halfreif, CT_Comparison, CMPT_LE_0, VT_Float, aux_float_le_zero_if_1__POST)); aCT.push_back(DCT("aux_float_lt_zero_if_1__POST", t_VFVIVFF, RIT_Halfreif, CT_Comparison, CMPT_LT_0, VT_Float, aux_float_lt_zero_if_1__POST)); aCT.push_back(DCT("equality_encoding__POST", t_VIAVI, RIT_Static, CT_Encode, CMPT_None, VT_Int, equality_encoding__POST)); aCT.push_back(DCT("set_in__POST", t_VISI, RIT_Static, CT_SetIn, CMPT_None, VT_Int, set_in__POST)); aCT.push_back(DCT("set_in_reif__POST", t_VISIVI, RIT_Reif, CT_SetIn, CMPT_None, VT_Int, set_in_reif__POST)); /// Registering all declared & compatible __POST constraints /// (First, cleanup FunctionIs' payload: -- ! doing now) for ( int i=0; imatchFn(env, ASTString(aCT[i].sFuncName), aCT[i].aParams, false); if (fi) { mCallTypes[fi] = aCT.data() + i; aCT[i].pfi = fi; // fi->pPayload = (void*)this; // std::cerr << " FOund declaration: " << aCT[i].sFuncName << std::endl; } else { aCT[i].pfi = 0; DBGOUT_MIPD ( " MIssing declaration: " << aCT[i].sFuncName ); return false; } } return true; } /// Registering all __POST calls' domain-constrained variables void register__POSTvariables() { EnvI& env = getEnv()->envi(); GCLock lock; Model& mFlat = *getEnv()->flat(); // First, cleanup VarDecls' payload which stores index in vVarDescr for( VarDeclIterator ivd=mFlat.begin_vardecls(); ivd!=mFlat.end_vardecls(); ++ivd ) { ivd->e()->payload(-1); } // Now add variables with non-contiguous domain for( VarDeclIterator ivd=mFlat.begin_vardecls(); ivd!=mFlat.end_vardecls(); ++ivd ) { VarDecl* vd0 = ivd->e(); bool fNonCtg = 0; if ( vd0->type().isint() ) { // currently only for int vars TODO if ( Expression* eDom = vd0->ti()->domain() ) { IntSetVal* dom = eval_intset( env, eDom ); fNonCtg = ( dom->size() > 1 ); } } if ( fNonCtg ) { DBGOUT_MIPD ( " Variable " << vd0->id()->str() << ": non-contiguous domain " << (*(vd0->ti()->domain())) ); if ( vd0->payload() == -1 ) { // ! yet visited vd0->payload( static_cast(vVarDescr.size()) ); vVarDescr.push_back( VarDescr( vd0, vd0->type().isint() ) ); // can use /prmTypes/ as well if (vd0->e()) checkInitExpr(vd0); } else { DBGOUT_MIPD__ ( " (already touched)" ); } ++MIPD__stats[ N_POSTs__domain ]; ++MIPD__stats[ N_POSTs__all ]; } } // Iterate thru original __POST constraints to mark constrained vars: for( ConstraintIterator ic=mFlat.begin_constraints(); ic != mFlat.end_constraints(); ++ic ) { if ( ic->removed() ) continue; if ( Call* c = ic->e()->dyn_cast() ) { auto ipct = mCallTypes.find(c->decl()); if ( ipct != mCallTypes.end() ) { // No ! here because might be deleted immediately in later versions. // ic->remove(); // mark removed at once MZN_MIPD__assert_hard( c->n_args() > 1 ); ++MIPD__stats[ N_POSTs__all ]; VarDecl* vd0 = expr2VarDecl(c->arg(0)); if ( 0==vd0 ) { DBGOUT_MIPD__ ( " Call " << *c << ": 1st arg not a VarDecl, removing if eq_encoding..." ); /// Only allow literals as main argument for equality_encoding if ( equality_encoding__POST==ipct->first ) // was MZN_MIPD__assert_hard before MZN 2017 ic->remove(); continue; // ignore this call } DBGOUT_MIPD__ ( " Call " << c->id().str() << " uses variable " << vd0->id()->str() ); if ( vd0->payload() == -1 ) { // ! yet visited vd0->payload( static_cast(vVarDescr.size()) ); vVarDescr.push_back( VarDescr( vd0, vd0->type().isint() ) ); // can use /prmTypes/ as well // bounds/domains later for each involved var TODO if (vd0->e()) checkInitExpr(vd0); } else { DBGOUT_MIPD__ ( " (already touched)" ); } DBGOUT_MIPD ( "" ); if ( equality_encoding__POST == c->decl() ) { MZN_MIPD__assert_hard( ! vVarDescr[ vd0->payload() ].pEqEncoding ); vVarDescr[ vd0->payload() ].pEqEncoding = &*ic; DBGOUT_MIPD ( " Variable " << vd0->id()->str() << " has eq_encode." ); } // + if has aux_ constraints? else vVarDescr[ vd0->payload() ].aCalls.push_back(&*ic); } } } MIPD__stats[ N_POSTs__varsDirect ] = static_cast(vVarDescr.size()); } // Should only be called on a newly added variable // OR when looking thru all non-touched vars /// Checks init expr of a variable /// Return true IFF new connection /// The bool param requires RHS to be POST-touched // Guido: can! be recursive in FZN bool checkInitExpr(VarDecl* vd, bool fCheckArg=false) { MZN_MIPD__assert_hard( vd->e() ); if ( ! vd->type().isint() && ! vd->type().isfloat() ) return false; if ( ! fCheckArg ) MZN_MIPD__assert_hard( vd->payload() >= 0 ); if ( Id* id = vd->e()->dyn_cast() ) { // const int f1 = ( vd->payload()>=0 ); // const int f2 = ( id->decl()->payload()>=0 ); if ( ! fCheckArg || ( id->decl()->payload()>=0 ) ) { DBGOUT_MIPD__ ( " Checking init expr " ); DBGOUT_MIPD_SELF( debugprint(vd) ); LinEq2Vars led; // FAILS: // led.vd = { vd, expr2VarDecl(id->decl()->e()) }; led.vd = { {vd, expr2VarDecl( vd->e() )} }; led.coefs = { {1.0, -1.0} }; led.rhs = 0.0; put2VarsConnection( led, false ); ++MIPD__stats[ N_POSTs__initexpr1id ]; if ( id->decl()->e() ) // no initexpr for initexpr FAILS on cc-base.mzn checkInitExpr( id->decl() ); return true; // in any case } } else if ( Call* c = vd->e()->dyn_cast() ) { if ( lin_exp_int==c->decl() || lin_exp_float==c->decl() ) { // std::cerr << " !E call " << std::flush; // debugprint(c); MZN_MIPD__assert_hard(c->n_args() == 3 ); // ArrayLit* al = c->args()[1]->dyn_cast(); ArrayLit* al = follow_id(c->arg(1))->cast(); MZN_MIPD__assert_hard( al ); MZN_MIPD__assert_hard( al->size() >= 1 ); if ( al->size() == 1 ) { // 1-term scalar product in the rhs LinEq2Vars led; led.vd = { {vd, expr2VarDecl((*al)[0])} }; // const int f1 = ( vd->payload()>=0 ); // const int f2 = ( led.vd[1]->payload()>=0 ); if ( ! fCheckArg || ( led.vd[1]->payload()>=0 ) ) { // Can use a!her map here: // if ( sCallLinEq2.end() != sCallLinEq2.find(c) ) // continue; // sCallLinEq2.insert(c); // memorize this call DBGOUT_MIPD__ ( " REG 1-LINEXP " ); DBGOUT_MIPD_SELF ( debugprint(vd) ); std::array coef0; expr2Array(c->arg(0), coef0); led.coefs = { {-1.0, coef0[0]} }; led.rhs = -expr2Const(c->arg(2)); // MINUS put2VarsConnection( led, false ); ++MIPD__stats[ N_POSTs__initexpr1linexp ]; if ( led.vd[1]->e() ) // no initexpr for initexpr FAILS TODO checkInitExpr( led.vd[1] ); return true; // in any case } } else if ( true ) { // check larger views always. OK? TODO // if ( vd->payload()>=0 ) { // larger views // TODO should be here? // std::cerr << " LE_" << al->v().size() << ' ' << std::flush; DBGOUT_MIPD ( " REG N-LINEXP " ); DBGOUT_MIPD_SELF ( debugprint( vd ) ); // Checking all but adding only touched defined vars? return findOrAddDefining( vd->id(), c ); } } } return false; } /// Build var cliques (i.e. of var pairs viewing each other) void constructVarViewCliques() { // std::cerr << " Model: " << std::endl; // debugprint(getEnv()->flat()); // TAgenda agenda(vVarDescr.size()), agendaNext; // for ( int i=0; i(vVarDescr.size()); } void propagateViews(bool &fChanges) { // EnvI& env = getEnv()->envi(); GCLock lock; // Iterate thru original 2-variable equalities to mark views: Model& mFlat = *getEnv()->flat(); DBGOUT_MIPD ( " CHECK ALL INITEXPR if they access a touched variable:" ); for( VarDeclIterator ivd=mFlat.begin_vardecls(); ivd!=mFlat.end_vardecls(); ++ivd ) { if ( ivd->removed() ) continue; if ( ivd->e()->e() && ivd->e()->payload()<0 // untouched && ( ivd->e()->type().isint() || ivd->e()->type().isfloat() ) ) // scalars if ( checkInitExpr(ivd->e(), true) ) fChanges = true; } DBGOUT_MIPD ( " CHECK ALL CONSTRAINTS for 2-var equations:" ); for( ConstraintIterator ic=mFlat.begin_constraints(); ic != mFlat.end_constraints(); ++ic ) { // std::cerr << " SEE constraint: " << " "; // debugprint(&*ic); // debugprint(c->decl()); if ( ic->removed() ) continue; if ( Call* c = ic->e()->dyn_cast() ) { const bool fIntLinEq = int_lin_eq==c->decl(); const bool fFloatLinEq = float_lin_eq==c->decl(); if ( fIntLinEq || fFloatLinEq ) { // std::cerr << " !E call " << std::flush; // debugprint(c); MZN_MIPD__assert_hard( c->n_args() == 3 ); ArrayLit* al = follow_id(c->arg(1))->cast(); MZN_MIPD__assert_hard( al ); if ( al->size() == 2 ) { // 2-term eqn LinEq2Vars led; expr2DeclArray(c->arg(1), led.vd); // At least 1 touched var: if ( led.vd[0]->payload() >= 0 || led.vd[1]->payload()>=0 ) { if ( sCallLinEq2.end() != sCallLinEq2.find(c) ) continue; sCallLinEq2.insert(c); // memorize this call DBGOUT_MIPD ( " REG 2-call " ); DBGOUT_MIPD_SELF ( debugprint(c) ); led.rhs = expr2Const(c->arg(2)); expr2Array(c->arg(0), led.coefs); MZN_MIPD__assert_hard( 2 == led.coefs.size() ); fChanges = true; put2VarsConnection( led ); ++MIPD__stats[ fIntLinEq ? N_POSTs__eq2intlineq : N_POSTs__eq2floatlineq ]; } } else if ( al->size() == 1 ) { static int nn=0; if ( ++nn <= 7 ) { std::cerr << " MIPD: LIN_EQ with 1 variable::: " << std::flush; std::cerr << (*c) << std::endl; } } else { // larger eqns // TODO should be here? auto eVD = getAnnotation( c->ann(), constants().ann.defines_var ); if ( eVD ) { if ( sCallLinEqN.end() != sCallLinEqN.find(c) ) continue; sCallLinEqN.insert(c); // memorize this call DBGOUT_MIPD ( " REG N-call " ); DBGOUT_MIPD_SELF ( debugprint(c) ); Call* pC = eVD->dyn_cast(); MZN_MIPD__assert_hard( pC ); MZN_MIPD__assert_hard( pC->n_args() ); // Checking all but adding only touched defined vars? Seems too long. VarDecl* vd = expr2VarDecl( pC->arg(0) ); if ( vd->payload()>=0 ) // only if touched if ( findOrAddDefining( pC->arg(0), c ) ) fChanges = true; } } } else // const bool fI2F = (int2float==c->decl()); // const bool fIVR = (constants().var_redef==c->decl()); // if ( fI2F || fIVR ) { if ( int2float==c->decl() || constants().var_redef==c->decl() ) { // std::cerr << " !E call " << std::flush; // debugprint(c); MZN_MIPD__assert_hard( c->n_args() == 2 ); LinEq2Vars led; // led.vd.resize(2); led.vd[0] = expr2VarDecl(c->arg(0)); led.vd[1] = expr2VarDecl(c->arg(1)); // At least 1 touched var: if ( led.vd[0]->payload() >= 0 || led.vd[1]->payload()>=0 ) { if ( sCallInt2Float.end() != sCallInt2Float.find(c) ) continue; sCallInt2Float.insert(c); // memorize this call DBGOUT_MIPD ( " REG call " ); DBGOUT_MIPD_SELF ( debugprint(c) ); led.rhs = 0.0; led.coefs = { {1.0, -1.0} }; fChanges = true; put2VarsConnection( led ); ++MIPD__stats[ int2float==c->decl() ? N_POSTs__int2float : N_POSTs__internalvarredef ]; } } } } } /// This vector stores the linear part of a general view /// x = + rhs typedef std::vector > TLinExpLin; /// This struct has data describing the rest of a general view struct NViewData { VarDecl* pVarDefined = 0; double coef0 = 1.0; double rhs; }; typedef std::map NViewMap; NViewMap mNViews; /// compare to an existing defining linexp, || just add it to the map /// adds only touched defined vars /// return true iff new linear connection // linexp: z = a^T x+b // _lin_eq: a^T x == b bool findOrAddDefining( Expression* exp, Call* pC ) { Id* pId = exp->dyn_cast(); MZN_MIPD__assert_hard( pId ); VarDecl* vd = pId->decl(); MZN_MIPD__assert_hard( vd ); MZN_MIPD__assert_hard( pC->n_args()==3 ); TLinExpLin rhsLin; NViewData nVRest; nVRest.pVarDefined = vd; nVRest.rhs = expr2Const( pC->arg(2) ); std::vector vars; expr2DeclArray( pC->arg(1), vars ); std::vector coefs; expr2Array( pC->arg(0), coefs ); MZN_MIPD__assert_hard( vars.size()==coefs.size() ); int nVD=0; for ( int i=0; i=nVD ); std::sort( rhsLin.begin(), rhsLin.end() ); // Divide the equation by the 1st coef const double coef1 = rhsLin.begin()->second; MZN_MIPD__assert_hard( 0.0!=std::fabs( coef1 ) ); nVRest.coef0 /= coef1; nVRest.rhs /= coef1; for ( auto& rhsL : rhsLin ) rhsL.second /= coef1; auto it = mNViews.find( rhsLin ); if ( mNViews.end()!=it && nVRest.pVarDefined!=it->second.pVarDefined) { // don't connect to itself LinEq2Vars leq; leq.vd = { {nVRest.pVarDefined, it->second.pVarDefined} }; leq.coefs = { {nVRest.coef0, -it->second.coef0} }; // +, - leq.rhs = nVRest.rhs - it->second.rhs; put2VarsConnection( leq, false ); ++MIPD__stats[ nVD ? N_POSTs__eqNlineq : N_POSTs__initexprN ]; return true; } else { if ( vd->payload()>=0 ) { // only touched mNViews[ rhsLin ] = nVRest; return true; // can lead to a new connection } } return false; } void propagateImplViews(bool &fChanges) { // EnvI& env = getEnv()->envi(); GCLock lock; // TODO } /// Could be better to mark the calls instead: std::unordered_set sCallLinEq2, sCallInt2Float, sCallLinEqN; class TClique : public std::vector { // need more info? public: /// This function takes the 1st variable && relates all to it /// Return false if contrad / disconnected graph // bool findRelations0() { // return true; // } }; typedef std::vector TCLiqueList; TCLiqueList aCliques; /// register a 2-variable lin eq /// add it to the var clique, joining the participants' cliques if needed void put2VarsConnection( LinEq2Vars& led, bool fCheckinitExpr=true ) { MZN_MIPD__assert_hard( led.coefs.size() == led.vd.size() ); MZN_MIPD__assert_hard( led.vd.size() == 2 ); DBGOUT_MIPD__ ( " Register 2-var connection: " << led ); /// Check it's not same 2 vars if (led.vd[0]==led.vd[1]) { MZN_MIPD__assert_soft(0, "MIPD: STRANGE: registering var connection to itself: " << led << ", skipping"); MZN_MIPD__ASSERT_FOR_SAT(fabs(led.coefs[0]+led.coefs[1]) < 1e-6, // TODO param getEnv()->envi(), led.vd[0]->loc(), "Var connection to itself seems to indicate UNSAT: " << led); return; } // register if new variables // std::vector fHaveClq(led.vd.size(), false); int nCliqueAvailable = -1; for ( auto vd : led.vd ) { if ( vd->payload() < 0 ) { // ! yet visited vd->payload( static_cast(vVarDescr.size()) ); vVarDescr.push_back( VarDescr( vd, vd->type().isint() ) ); // can use /prmTypes/ as well if ( fCheckinitExpr && vd->e() ) checkInitExpr(vd); } else { int nMaybeClq = vVarDescr[vd->payload()].nClique; if ( nMaybeClq >= 0 ) nCliqueAvailable = nMaybeClq; // MZN_MIPD__assert_hard( nCliqueAvailable>=0 ); // fHaveClq[i] = true; } } if ( nCliqueAvailable < 0 ) { // no clique found nCliqueAvailable = static_cast(aCliques.size()); aCliques.resize(aCliques.size() + 1); } DBGOUT_MIPD ( " ...adding to clique " << nCliqueAvailable << " of size " << aCliques[nCliqueAvailable].size() ); TClique& clqNew = aCliques[nCliqueAvailable]; clqNew.push_back( led ); for ( auto vd : led.vd ) { // merging cliques int& nMaybeClq = vVarDescr[vd->payload()].nClique; if ( nMaybeClq >= 0 && nMaybeClq != nCliqueAvailable ) { TClique& clqOld = aCliques[nMaybeClq]; MZN_MIPD__assert_hard( clqOld.size() ); for ( auto& eq2 : clqOld ) { for ( auto vd : eq2.vd ) { // point all the variables to the new clique vVarDescr[ vd->payload() ].nClique = nCliqueAvailable; } } clqNew.insert(clqNew.end(), clqOld.begin(), clqOld.end()); clqOld.clear(); // Can use C++11 move TODO DBGOUT_MIPD ( " +++ Joining cliques" ); } nMaybeClq = nCliqueAvailable; // Could mark as 'unused' TODO } } /// Finds a clique variable to which all domain constr are related class TCliqueSorter { MIPD& mipd; const int iVarStart; // this is the first var to which all others are related public: // VarDecl* varRef0=0; // this is the first var to which all others are related VarDecl* varRef1=0; // this is the 2nd main reference. // it is a var with eq_encode, || // an (integer if any) variable with the least rel. factor bool fRef1HasEqEncode=false; /// This map stores the relations y = ax+b of all the clique's vars to y typedef std::unordered_map > TMapVars; TMapVars mRef0, mRef1; // to the main var 0, 1 class TMatrixVars : public std::unordered_map { public: /// Check existing connection template bool checkExistingArc(IVarDecl begV, double A, double B, bool fReportRepeat=true) { auto it1 = this->find(*begV); if ( this->end() != it1 ) { auto it2 = it1->second.find(*(begV+1)); if ( it1->second.end() != it2 ) { MZN_MIPD__assert_hard( std::fabs( it2->second.first - A ) < 1e-6 * std::max( std::fabs(it2->second.first), std::fabs(A) ) ); MZN_MIPD__assert_hard( std::fabs( it2->second.second - B ) < 1e-6 * std::max( std::fabs(it2->second.second), std::fabs(B) ) + 1e-6 ); MZN_MIPD__assert_hard( std::fabs( A ) != 0.0 ); MZN_MIPD__assert_soft ( !fVerbose || std::fabs( A ) > 1e-12, " Very small coef: " << (*begV)->id()->str() << " = " << A << " * " << (*(begV+1))->id()->str() << " + " << B ); if ( fReportRepeat ) MZN_MIPD__assert_soft ( !fVerbose, "LinEqGraph: eqn between " << (*begV)->id()->str() << " && " << (*(begV+1))->id()->str() << " is repeated. " ); return true; } } return false; } }; class LinEqGraph : public TMatrixVars { public: static double dCoefMin, dCoefMax; /// Stores the arc (x1, x2) as x1 = a*x2 + b /// so that a constraint on x2, say x2<=c <-> f, /// is equivalent to one for x1: x1 <=/>= a*c+b <-> f //// ( the other way involves division: //// so that a constraint on x1, say x1<=c <-> f, //// can easily be converted into one for x2 as a*x2 <= c-b <-> f //// <=> x2 (care for sign) (c-b)/a <-> f ) template void addArc(ICoef begC, IVarDecl begV, double rhs) { MZN_MIPD__assert_soft( !fVerbose || std::fabs( *begC ) >= 1e-10, " Vars " << (*begV)->id()->str() << " to " << (*(begV+1))->id()->str() << ": coef=" << (*begC) ); // Transform Ax+By=C into x = -B/Ay+C/A const double negBA = -(*(begC+1))/(*begC); const double CA = rhs/(*begC); checkExistingArc(begV, negBA, CA); (*this)[*begV][*(begV+1)] = std::make_pair(negBA, CA); const double dCoefAbs = std::fabs( negBA ); if ( dCoefAbsdCoefMax ) dCoefMax = dCoefAbs; } void addEdge(const LinEq2Vars& led) { addArc( led.coefs.begin(), led.vd.begin(), led.rhs ); addArc( led.coefs.rbegin(), led.vd.rbegin(), led.rhs ); } /// Propagate linear relations from the given variable void propagate(iterator itStart, TMapVars& mWhereStore) { MZN_MIPD__assert_hard( this->end()!=itStart ); TMatrixVars mTemp; mTemp[itStart->first] = itStart->second; // init with existing DBGOUT_MIPD ( "Propagation started from " << itStart->first->id()->str() << " having " << itStart->second.size() << " connections" ); propagate2(itStart, itStart, std::make_pair(1.0, 0.0), mTemp); mWhereStore = mTemp.begin()->second; MZN_MIPD__assert_hard_msg( mWhereStore.size() == this->size()-1, "Variable " << (*(mTemp.begin()->first)) << " should be connected to all others in the clique, but " << "|edges|==" << mWhereStore.size() << ", |all nodes|==" << this->size() ); } /// Propagate linear relations from it1 via it2 void propagate2(iterator itSrc, iterator itVia, std::pair rel, TMatrixVars& mWhereStore) { for ( auto itDst=itVia->second.begin(); itDst!=itVia->second.end(); ++itDst ) { // Transform x1=A1x2+B1, x2=A2x3+B2 into x1=A1A2x3+A1B2+B1 if ( itDst->first == itSrc->first ) continue; const double A1A2 = rel.first * itDst->second.first; const double A1B2plusB1 = rel.first*itDst->second.second + rel.second; bool fDive=true; if ( itSrc != itVia ) { PVarDecl vd[2] = { itSrc->first, itDst->first }; if ( ! mWhereStore.checkExistingArc(vd, A1A2, A1B2plusB1, false) ) { mWhereStore[vd[0]][vd[1]] = std::make_pair(A1A2, A1B2plusB1); DBGOUT_MIPD ( " PROPAGATING: " << vd[0]->id()->str() << " = " << A1A2 << " * " << vd[1]->id()->str() << " + " << A1B2plusB1 ); } else fDive = false; } if ( fDive ) { auto itDST = this->find(itDst->first); MZN_MIPD__assert_hard( this->end() != itDST ); propagate2(itSrc, itDST, std::make_pair(A1A2, A1B2plusB1), mWhereStore); } } } }; LinEqGraph leg; TCliqueSorter(MIPD* pm, int iv) : mipd(*pm), iVarStart(iv) { } void doRelate() { MZN_MIPD__assert_hard( mipd.vVarDescr[iVarStart].nClique >= 0 ); const TClique& clq = mipd.aCliques[ mipd.vVarDescr[iVarStart].nClique ]; for ( auto& eq2 : clq ) { leg.addEdge(eq2); } DBGOUT_MIPD ( " Clique " << mipd.vVarDescr[iVarStart].nClique << ": " << leg.size() << " variables, " << clq.size() << " connections." ); for ( auto it1=leg.begin(); it1!=leg.end(); ++it1 ) mipd.vVarDescr[ it1->first->payload() ].fDomainConstrProcessed = true; // Propagate the 1st var's relations: leg.propagate(leg.begin(), mRef0); // Find a best main variable according to: // 1. isInt 2. hasEqEncode 3. abs linFactor to ref0 varRef1 = leg.begin()->first; std::array aCrit = { { (double)mipd.vVarDescr[varRef1->payload()].fInt, static_cast(mipd.vVarDescr[varRef1->payload()].pEqEncoding!=NULL), 1.0 } }; for ( auto it2=mRef0.begin(); it2!=mRef0.end(); ++it2 ) { VarDescr& vard = mipd.vVarDescr[ it2->first->payload() ]; std::array aCrit1 = { { (double)vard.fInt, static_cast(vard.pEqEncoding!=NULL), std::fabs(it2->second.first) } }; if ( aCrit1 > aCrit ) { varRef1 = it2->first; aCrit = aCrit1; } } leg.propagate(leg.find(varRef1), mRef1); } }; // class TCliqueSorter /// Build a domain decomposition for a clique /// a clique can consist of just 1 var without a clique object class DomainDecomp { public: MIPD& mipd; const int iVarStart; TCliqueSorter cls; SetOfIntvReal sDomain; DomainDecomp(MIPD* pm, int iv) : mipd(*pm), iVarStart(iv), cls(pm, iv) { sDomain.insert(IntvReal()); // the decomposed domain. Init to +-inf } void doProcess() { // Choose the main variable && relate all others to it const int nClique = mipd.vVarDescr[iVarStart].nClique; if ( nClique >= 0 ) { cls.doRelate(); } else cls.varRef1 = mipd.vVarDescr[ iVarStart ].vd; // Adding itself: cls.mRef1[ cls.varRef1 ] = std::make_pair( 1.0, 0.0 ); int iVarRef1 = cls.varRef1->payload(); MZN_MIPD__assert_hard ( nClique == mipd.vVarDescr[iVarRef1].nClique ); cls.fRef1HasEqEncode = (mipd.vVarDescr[ iVarRef1 ].pEqEncoding != NULL); // First, construct the domain decomposition in any case // projectVariableConstr( cls.varRef1, std::make_pair(1.0, 0.0) ); // if ( nClique >= 0 ) { for ( auto& iRef1 : cls.mRef1 ) { projectVariableConstr( iRef1.first, iRef1.second ); } DBGOUT_MIPD( "Clique " << nClique << ": main ref var " <id()->str() << ", domain dec: " << sDomain ); MZN_MIPD__ASSERT_FOR_SAT( sDomain.size()!=0, mipd.getEnv()->envi(), cls.varRef1->loc(), "clique " << nClique << ": main ref var " << *cls.varRef1->id() << ", domain decomposition seems empty: " << sDomain ); MZN_MIPD__FLATTENING_ERROR__IF_NOT (sDomain.checkFiniteBounds(), mipd.getEnv()->envi(),cls.varRef1->loc(), "variable " << *cls.varRef1->id() << " needs finite bounds for linearisation." " Or, use indicator constraints. " << "Current domain is " << sDomain); MZN_MIPD__assert_hard( sDomain.checkDisjunctStrict() ); makeRangeDomains(); // Then, use equality_encoding if available if ( cls.fRef1HasEqEncode ) { syncWithEqEncoding(); syncOtherEqEncodings(); } else { // ! cls.fRef1HasEqEncode if ( sDomain.size()>=2 ) { // need to simplify stuff otherwise considerDenseEncoding(); createDomainFlags(); } } implement__POSTs(); // Statistics if ( sDomain.size() < MIPD__stats[ N_POSTs__NSubintvMin ] ) MIPD__stats[ N_POSTs__NSubintvMin ] = static_cast(sDomain.size()); MIPD__stats[ N_POSTs__NSubintvSum ] += sDomain.size(); if ( sDomain.size() > MIPD__stats[ N_POSTs__NSubintvMax ] ) MIPD__stats[ N_POSTs__NSubintvMax ] = static_cast(sDomain.size()); for ( auto& intv : sDomain ) { const auto nSubSize = intv.right - intv.left; if ( nSubSize < MIPD__stats[ N_POSTs__SubSizeMin ] ) MIPD__stats[ N_POSTs__SubSizeMin ] = nSubSize; MIPD__stats[ N_POSTs__SubSizeSum ] += nSubSize; if ( nSubSize > MIPD__stats[ N_POSTs__SubSizeMax ] ) MIPD__stats[ N_POSTs__SubSizeMax ] = nSubSize; } if ( cls.fRef1HasEqEncode ) ++MIPD__stats[ N_POSTs__cliquesWithEqEncode ]; } /// Project the domain-related constraints of a variable into the clique /// Deltas should be scaled but to a minimum of the target's discr /// COmparison sense changes on negated vars void projectVariableConstr( VarDecl* vd, std::pair eq1 ) { DBGOUT_MIPD__( " MIPD: projecting variable " ); DBGOUT_MIPD_SELF( debugprint(vd) ); // Always check if domain becomes empty? TODO const double A = eq1.first; // vd = A*arg + B. conversion const double B = eq1.second; // process domain info double lb=B, ub=A+B; // projected bounds for bool if ( vd->ti()->domain() ) { if ( vd->type().isint() || vd->type().isfloat() ) { // INT VAR OR FLOAT VAR SetOfIntvReal sD1; convertIntSet( vd->ti()->domain(), sD1, cls.varRef1, A, B ); sDomain.intersect(sD1); DBGOUT_MIPD( " Clique domain after proj of the init. domain " << sD1 << " of " << (vd->type().isint() ? "varint" : "varfloat") << A << " * " << vd->id()->str() << " + " << B << ": " << sDomain ); auto bnds = sD1.getBounds(); lb = bnds.left; ub = bnds.right; } else { MZN_MIPD__FLATTENING_ERROR__IF_NOT( 0, mipd.getEnv()->envi(), cls.varRef1->loc(), "Variable " << vd->id()->str() << " of type " << vd->type().toString(mipd.__env->envi()) << " has a domain." ); } // /// Deleting var domain: // vd->ti()->domain( NULL ); } else { if ( NULL==vd->ti()->domain() && ! vd->type().isbool() ) { lb = IntvReal::infMinus(); ub = IntvReal::infPlus(); } } auto bnds = sDomain.getBounds(); // can change TODO // process calls. Can use the constr type info. auto& aCalls = mipd.vVarDescr[ vd->payload() ].aCalls; for ( Item* pItem : aCalls ) { ConstraintI* pCI = pItem->dyn_cast(); MZN_MIPD__assert_hard( pCI!=nullptr ); Call* pCall = pCI->e()->dyn_cast(); MZN_MIPD__assert_hard( pCall!=nullptr ); DBGOUT_MIPD__( "PROPAG CALL " ); DBGOUT_MIPD_SELF( debugprint( pCall ) ); // check the bounds for bool in reifs? TODO auto ipct = mipd.mCallTypes.find( pCall->decl() ); MZN_MIPD__assert_hard( mipd.mCallTypes.end() != ipct ); const DCT& dct = *ipct->second; int nCmpType_ADAPTED = dct.nCmpType; if ( A < 0.0 ) { // negative factor if ( std::abs( nCmpType_ADAPTED ) >= 4 ) // inequality nCmpType_ADAPTED = -nCmpType_ADAPTED; } switch ( dct.nConstrType ) { case CT_SetIn: { SetOfIntvReal SS; convertIntSet( pCall->arg(1), SS, cls.varRef1, A, B ); if ( RIT_Static == dct.nReifType ) { sDomain.intersect(SS); ++MIPD__stats[ N_POSTs__setIn ]; } else { sDomain.cutDeltas(SS, std::max( 1.0, std::fabs( A ) ) ); // deltas to scale ++MIPD__stats[ N_POSTs__setInReif ]; } } break; case CT_Comparison: if ( RIT_Reif == dct.nReifType ) { const double rhs = ( mipd.aux_float_lt_zero_iff_1__POST == pCall->decl() ) ? B /* + A*0.0, relating to 0 */ // The 2nd argument is constant: : A * mipd.expr2Const( pCall->arg(1) ) + B; const double rhsUp = rndUpIfInt( cls.varRef1, rhs ); const double rhsDown = rndDownIfInt( cls.varRef1, rhs ); const double rhsRnd = rndIfInt( cls.varRef1, rhs ); /// Strictly, for delta we should finish domain reductions first... TODO? const double delta = computeDelta( cls.varRef1, vd, bnds, A, pCall, 3 ); switch ( nCmpType_ADAPTED ) { case CMPT_LE: sDomain.cutDeltas( IntvReal::infMinus(), rhsDown, delta ); break; case CMPT_GE: sDomain.cutDeltas( rhsUp, IntvReal::infPlus(), delta ); break; case CMPT_LT_0: sDomain.cutDeltas( IntvReal::infMinus(), rhsDown-delta, delta ); break; case CMPT_GT_0: sDomain.cutDeltas( rhsUp+delta, IntvReal::infPlus(), delta ); break; case CMPT_EQ: if ( ! ( cls.varRef1->type().isint() && // skip if int target var std::fabs( rhs - rhsRnd ) > INT_EPS ) ) // && fract value sDomain.cutDeltas( rhsRnd, rhsRnd, delta ); break; default: MZN_MIPD__assert_hard_msg( 0, " No other reified cmp type " ); } ++MIPD__stats[ ( vd->ti()->type().isint() ) ? N_POSTs__intCmpReif : N_POSTs__floatCmpReif ]; } else if ( RIT_Static == dct.nReifType ) { // _ne, later maybe static ineq TODO MZN_MIPD__assert_hard( CMPT_NE == dct.nCmpType ); const double rhs = A * mipd.expr2Const( pCall->arg(1) ) + B; const double rhsRnd = rndIfInt( cls.varRef1, rhs ); bool fSkipNE = ( cls.varRef1->type().isint() && std::fabs( rhs - rhsRnd ) > INT_EPS ); if ( ! fSkipNE ) { const double delta = computeDelta( cls.varRef1, vd, bnds, A, pCall, 2 ); sDomain.cutOut( { rhsRnd-delta, rhsRnd+delta } ); } ++MIPD__stats[ ( vd->ti()->type().isint() ) ? N_POSTs__intNE : N_POSTs__floatNE ]; } else { // aux_ relate to 0.0 // But we don't modify domain splitting for them currently ++MIPD__stats[ ( vd->ti()->type().isint() ) ? N_POSTs__intAux : N_POSTs__floatAux ]; MZN_MIPD__assert_hard ( RIT_Halfreif==dct.nReifType ); // const double rhs = B; // + A*0 // const double delta = vd->type().isint() ? 1.0 : 1e-5; // TODO : eps } break; case CT_Encode: // See if any further constraints here? TODO ++MIPD__stats[ N_POSTs__eq_encode ]; break; default: MZN_MIPD__assert_hard_msg( 0, "Unknown constraint type" ); } } DBGOUT_MIPD( " Clique domain after proj of " << A << " * " << vd->id()->str() << " + " << B << ": " << sDomain ); } static double rndIfInt( VarDecl* vdTarget, double v ) { return vdTarget->type().isint() ? std::round( v ) : v; } static double rndIfBothInt( VarDecl* vdTarget, double v ) { if ( !vdTarget->type().isint() ) return v; const double vRnd = std::round( v ); return (fabs( v-vRnd )type().isint() ? std::ceil( v-INT_EPS ) : v; } static double rndDownIfInt( VarDecl* vdTarget, double v ) { return vdTarget->type().isint() ? std::floor( v+INT_EPS ) : v; } void makeRangeDomains() { auto bnds = sDomain.getBounds(); for ( auto& iRef1 : cls.mRef1 ) { VarDecl* vd = iRef1.first; // projecting the bounds back: double lb0 = ( bnds.left - iRef1.second.second ) / iRef1.second.first; double ub0 = ( bnds.right - iRef1.second.second ) / iRef1.second.first; if ( lb0 > ub0 ) { MZN_MIPD__assert_hard( iRef1.second.first < 0.0 ); std::swap( lb0, ub0 ); } if ( vd->type().isint() ) { lb0 = rndUpIfInt( vd, lb0 ); ub0 = rndDownIfInt( vd, ub0 ); } setVarDomain( vd, lb0, ub0); } } /// tightens element bounds in the existing eq_encoding of varRef1 /// necessary because if one exists, int_ne is not translated into it /// Can also back-check from there? TODO /// And further checks TODO void syncWithEqEncoding() { std::vector pp; auto bnds = sDomain.getBounds(); const long long iMin = mipd.expr2ExprArray( mipd.vVarDescr[ cls.varRef1->payload() ].pEqEncoding->e()->dyn_cast()->arg(1), pp ); MZN_MIPD__assert_hard( pp.size() >= bnds.right-bnds.left+1 ); MZN_MIPD__assert_hard( iMin<=bnds.left ); long long vEE = iMin; DBGOUT_MIPD__( " SYNC EQ_ENCODE( " << (*cls.varRef1) << ", bitflags: " << *(mipd.vVarDescr[ cls.varRef1->payload() ].pEqEncoding->e()->dyn_cast()->arg(1)) << " ): SETTING 0 FLAGS FOR VALUES: " ); for ( auto& intv : sDomain ) { for ( ; vEE < intv.left; ++vEE ) { if ( vEE >= static_cast(iMin+pp.size()) ) return; if ( pp[ vEE-iMin ]->isa() ) if ( pp[ vEE-iMin ]->dyn_cast()->decl()->type().isvar() ) { DBGOUT_MIPD__( vEE << ", " ); setVarDomain( pp[ vEE-iMin ]->dyn_cast()->decl(), 0.0, 0.0 ); } } vEE = static_cast(intv.right+1); } for ( ; vEE < static_cast(iMin+pp.size()); ++vEE ) { if ( pp[ vEE-iMin ]->isa() ) if ( pp[ vEE-iMin ]->dyn_cast()->decl()->type().isvar() ) { DBGOUT_MIPD__( vEE << ", " ); setVarDomain( pp[ vEE-iMin ]->dyn_cast()->decl(), 0.0, 0.0 ); } } DBGOUT_MIPD( "" ); } /// sync varRef1's eq_encoding with those of other variables void syncOtherEqEncodings() { // TODO This could be in the var projection? No, need the final domain } /// Depending on params, /// create an equality encoding for an integer variable /// TODO What if a float's domain is discrete? void considerDenseEncoding() { if ( cls.varRef1->id()->type().isint() ) { if ( sDomain.max_interval() <= mipd.nMaxIntv2Bits || sDomain.card_int() <= mipd.dMaxNValueDensity * sDomain.size() ) { sDomain.split2Bits(); ++MIPD__stats[ N_POSTs__clEEEnforced ]; } } } /// if ! eq_encoding, creates a flag for each subinterval in the domain /// && constrains sum(flags)==1 void createDomainFlags() { std::vector vVars( sDomain.size() ); // flags for each subinterval std::vector vIntvLB( sDomain.size() + 1 ), vIntvUB__( sDomain.size() + 1 ); int i=0; double dMaxIntv=-1.0; for ( auto& intv : sDomain ) { intv.varFlag = addIntVar( 0.0, 1.0 ); vVars[i] = intv.varFlag->id(); vIntvLB[i] = intv.left; vIntvUB__[i] = -intv.right; dMaxIntv = std::max( dMaxIntv, intv.right-intv.left ); ++i; } // Sum of flags == 1 std::vector ones( sDomain.size(), 1.0 ); addLinConstr( ones, vVars, CMPT_EQ, 1.0 ); // Domain decomp vVars.push_back( cls.varRef1->id() ); vIntvLB[i] = -1.0; // var1 >= sum(LBi*flagi) /// STRICT equality encoding if small intervals if ( dMaxIntv > 1e-6 ) { // EPS = param? TODO vIntvUB__[i] = 1.0; // var1 <= sum(UBi*flagi) addLinConstr( vIntvLB, vVars, CMPT_LE, 0.0 ); addLinConstr( vIntvUB__, vVars, CMPT_LE, 0.0 ); } else { ++MIPD__stats[ N_POSTs__clEEFound ]; addLinConstr( vIntvLB, vVars, CMPT_EQ, 0.0 ); } } /// deletes them as well void implement__POSTs() { auto bnds = sDomain.getBounds(); for ( auto& iRef1 : cls.mRef1 ) { // DBGOUT_MIPD__( " MIPD: implementing constraints of variable " ); // DBGOUT_MIPD_SELF( debugprint(vd) ); VarDecl* vd = iRef1.first; auto eq1 = iRef1.second; const double A = eq1.first; // vd = A*arg + B. conversion const double B = eq1.second; // process calls. Can use the constr type info. auto& aCalls = mipd.vVarDescr[ vd->payload() ].aCalls; for ( Item* pItem : aCalls ) { ConstraintI* pCI = pItem->dyn_cast(); MZN_MIPD__assert_hard( pCI ); Call* pCall = pCI->e()->dyn_cast(); MZN_MIPD__assert_hard( pCall ); DBGOUT_MIPD__( "IMPL CALL " ); DBGOUT_MIPD_SELF( debugprint( pCall ) ); // check the bounds for bool in reifs? TODO auto ipct = mipd.mCallTypes.find( pCall->decl() ); MZN_MIPD__assert_hard( mipd.mCallTypes.end() != ipct ); const DCT& dct = *ipct->second; int nCmpType_ADAPTED = dct.nCmpType; if ( A < 0.0 ) { // negative factor if ( std::abs( nCmpType_ADAPTED ) >= 4 ) // inequality nCmpType_ADAPTED = -nCmpType_ADAPTED; } switch ( dct.nConstrType ) { case CT_SetIn: if ( RIT_Reif == dct.nReifType ) { SetOfIntvReal SS; convertIntSet( pCall->arg(1), SS, cls.varRef1, A, B ); relateReifFlag( pCall->arg(2), SS ); } break; case CT_Comparison: if ( RIT_Reif == dct.nReifType ) { const double rhs = ( mipd.aux_float_lt_zero_iff_1__POST == pCall->decl() ) ? B /* + A*0.0, relating to 0 */ // The 2nd argument is constant: : A * mipd.expr2Const( pCall->arg(1) ) + B; const double rhsUp = rndUpIfInt( cls.varRef1, rhs ); const double rhsDown = rndDownIfInt( cls.varRef1, rhs ); const double rhsRnd = rndIfBothInt( cls.varRef1, rhs ); // if the ref var is int, need to round almost-int values const double delta = computeDelta( cls.varRef1, vd, bnds, A, pCall, 3 ); switch ( nCmpType_ADAPTED ) { case CMPT_LE: relateReifFlag( pCall->arg(2), { { IntvReal::infMinus(), rhsDown } } ); break; case CMPT_GE: relateReifFlag( pCall->arg(2), { { rhsUp, IntvReal::infPlus() } } ); break; case CMPT_LT_0: relateReifFlag( pCall->arg(1), { { IntvReal::infMinus(), rhsDown-delta } }); break; case CMPT_GT_0: relateReifFlag( pCall->arg(1), { { rhsUp+delta, IntvReal::infPlus() } } ); break; case CMPT_EQ: relateReifFlag( pCall->arg(2), { { rhsRnd, rhsRnd } } ); break; // ... but if the value is sign. fractional for an int var, the flag is set=0 default: break; } } else if ( RIT_Static == dct.nReifType ) { // !hing here for NE MZN_MIPD__assert_hard( CMPT_NE == nCmpType_ADAPTED ); } else { // aux_ relate to 0.0 // But we don't modify domain splitting for them currently MZN_MIPD__assert_hard ( RIT_Halfreif==dct.nReifType ); double rhs = B; // + A*0 const double rhsUp = rndUpIfInt( cls.varRef1, rhs ); const double rhsDown = rndDownIfInt( cls.varRef1, rhs ); const double rhsRnd = rndIfInt( cls.varRef1, rhs ); double delta = 0.0; if ( mipd.aux_float_lt_zero_if_1__POST==pCall->decl() ) // only float && lt delta = computeDelta( cls.varRef1, vd, bnds, A, pCall, 3 ); if ( nCmpType_ADAPTED < 0 ) delta = -delta; if ( cls.varRef1->type().isint() && CMPT_EQ_0!=nCmpType_ADAPTED ) { if ( nCmpType_ADAPTED < 0 ) rhs = rhsDown; else rhs = rhsUp; } else { rhs += delta; } // Now we need rhs ! to be in the inner of the domain bool fUseDD = true; if ( ! cls.fRef1HasEqEncode ) { switch ( nCmpType_ADAPTED ) { case CMPT_EQ_0: { auto itLB = sDomain.lower_bound(rhsRnd); fUseDD = ( itLB->left==rhsRnd && itLB->right==rhsRnd ); // exactly } break; case CMPT_LT_0: case CMPT_LE_0: { auto itUB = sDomain.upper_bound(rhsUp); bool fInner = false; if ( sDomain.begin() != itUB ) { --itUB; if ( itUB->right > rhs ) fInner = true; } fUseDD = ! fInner; } break; case CMPT_GT_0: case CMPT_GE_0: { auto itLB = sDomain.lower_bound(rhsDown); bool fInner = false; if ( sDomain.begin() != itLB ) { --itLB; if ( itLB->right >= rhs ) fInner = true; } fUseDD = ! fInner; } break; default: MZN_MIPD__assert_hard_msg( 0, "Unknown halfreif cmp type" ); } } if ( fUseDD ) { // use sDomain if ( CMPT_EQ_0==nCmpType_ADAPTED ) { relateReifFlag( pCall->arg(1), { { rhsRnd, rhsRnd } }, RIT_Halfreif ); } else if ( nCmpType_ADAPTED < 0 ) { relateReifFlag( pCall->arg(1), { { IntvReal::infMinus(), rhsDown } }, RIT_Halfreif ); } else { relateReifFlag( pCall->arg(1), { { rhsUp, IntvReal::infPlus() } }, RIT_Halfreif ); } } else { // use big-M DBGOUT_MIPD( " AUX BY BIG-Ms: " ); const bool fLE = ( CMPT_EQ_0==nCmpType_ADAPTED || 0>nCmpType_ADAPTED ); const bool fGE = ( CMPT_EQ_0==nCmpType_ADAPTED || 0ti()->type().isint() ? 1 : 2; cls.varRef1->ti()->type().isint() ? 1 : 2; // need the type of the variable to be constr MZN_MIPD__assert_hard( static_cast(nIdxInd)n_args() ); Expression* pInd = pCall->arg( nIdxInd ); if ( fLE && rhs < bnds.right ) { if ( rhs >= bnds.left ) { std::vector coefs = { 1.0, bnds.right-rhs }; // Use the float version of indicator: std::vector vars = { cls.varRef1->id(), pInd }; addLinConstr( coefs, vars, CMPT_LE, bnds.right ); } else setVarDomain( mipd.expr2VarDecl( pInd ), 0.0, 0.0 ); } if ( fGE && rhs > bnds.left ) { if ( rhs <= bnds.right ) { std::vector coefs = { -1.0, rhs-bnds.left }; std::vector vars = { cls.varRef1->id(), pInd }; addLinConstr( coefs, vars, CMPT_LE, -bnds.left ); } else setVarDomain( mipd.expr2VarDecl( pInd ), 0.0, 0.0 ); } } } break; case CT_Encode: // See if any further constraints here? TODO break; default: MZN_MIPD__assert_hard_msg( 0, "Unknown constraint type" ); } pItem->remove(); // removing the call } // removing the eq_encoding call if ( mipd.vVarDescr[ vd->payload() ].pEqEncoding ) mipd.vVarDescr[ vd->payload() ].pEqEncoding->remove(); } } /// sets varFlag = || <= sum( intv.varFlag : SS ) void relateReifFlag( Expression* expFlag, const SetOfIntvReal& SS, EnumReifType nRT=RIT_Reif ) { MZN_MIPD__assert_hard( RIT_Reif==nRT || RIT_Halfreif==nRT ); // MZN_MIPD__assert_hard( sDomain.size()>=2 ); VarDecl* varFlag = mipd.expr2VarDecl(expFlag); std::vector vIntvFlags; if ( cls.fRef1HasEqEncode ) { // use eq_encoding MZN_MIPD__assert_hard( varFlag->type().isint() ); std::vector pp; auto bnds = sDomain.getBounds(); const long long iMin = mipd.expr2ExprArray( mipd.vVarDescr[ cls.varRef1->payload() ].pEqEncoding->e()->dyn_cast()->arg(1), pp ); MZN_MIPD__assert_hard( pp.size() >= bnds.right-bnds.left+1 ); MZN_MIPD__assert_hard( iMin<=bnds.left ); for ( auto& intv : SS ) { for ( long long vv = (long long)std::max( double(iMin), ceil(intv.left) ); vv <= (long long)std::min( double(iMin)+pp.size()-1, floor(intv.right) ); ++vv ) { vIntvFlags.push_back( pp[vv-iMin] ); } } } else { MZN_MIPD__assert_hard( varFlag->type().isint() ); for ( auto& intv : SS ) { auto it1 = sDomain.lower_bound( intv.left ); auto it2 = sDomain.upper_bound( intv.right ); auto it11 = it1; // Check that we are looking ! into a subinterval: if ( sDomain.begin() != it11 ) { --it11; MZN_MIPD__assert_hard( it11->right < intv.left ); } auto it12 = it2; if ( sDomain.begin() != it12 ) { --it12; MZN_MIPD__assert_hard_msg( it12->right <= intv.right, " relateReifFlag for " << intv << " in " << sDomain ); } for ( it12 = it1; it12 != it2; ++it12 ) { if ( it12->varFlag ) vIntvFlags.push_back( it12->varFlag->id() ); else { MZN_MIPD__assert_hard( 1==sDomain.size() ); vIntvFlags.push_back( IntLit::a(1) ); // just a constant then } } } } if ( vIntvFlags.size() ) { // Could find out if reif is true -- TODO && see above for 1 subinterval std::vector onesm( vIntvFlags.size(), -1.0 ); onesm.push_back( 1.0 ); vIntvFlags.push_back( varFlag->id() ); EnumCmpType nCmpType = ( RIT_Reif==nRT ) ? CMPT_EQ : CMPT_LE; addLinConstr( onesm, vIntvFlags, nCmpType, 0.0 ); } else { // the reif is false setVarDomain( varFlag, 0.0, 0.0 ); } } void setVarDomain( VarDecl* vd, double lb, double ub ) { // need to check if the new range is in the previous bounds... TODO if ( vd->type().isfloat() ) { // if ( 0.0==lb && 0.0==ub ) { BinOp* newDom = new BinOp(Location().introduce(), FloatLit::a(lb), BOT_DOTDOT, FloatLit::a(ub)); vd->ti()->domain(newDom); DBGOUT_MIPD( " NULL OUT: " << vd->id()->str() ); // } } else if ( vd->type().isint() || vd->type().isbool() ) { SetLit* newDom = new SetLit(Location().introduce(),IntSetVal::a( static_cast(lb), static_cast(ub) )); // TypeInst* nti = copy(mipd.getEnv()->envi(),varFlag->ti())->cast(); // nti->domain(newDom); vd->ti()->domain(newDom); } else MZN_MIPD__assert_hard_msg( 0, "Unknown var type " ); } VarDecl* addIntVar(double LB, double UB) { // GCLock lock; // Cache them? Only location can be different TODO SetLit* newDom = new SetLit( Location().introduce(), IntSetVal::a( static_cast(LB), static_cast(UB) ) ); TypeInst* ti = new TypeInst(Location().introduce(),Type::varint(),newDom); VarDecl* newVar = new VarDecl(Location().introduce(),ti,mipd.getEnv()->envi().genId()); newVar->flat(newVar); mipd.getEnv()->envi().flat_addItem(new VarDeclI(Location().introduce(),newVar)); return newVar; } void addLinConstr( std::vector& coefs, std::vector& vars, EnumCmpType nCmpType, double rhs ) { std::vector args(3); MZN_MIPD__assert_hard( vars.size() >= 2 ); for ( auto v : vars ) { MZN_MIPD__assert_hard (&v); // throw std::string("addLinConstr: &var=NULL"); MZN_MIPD__assert_hard_msg ( v->isa() || v->isa() || v->isa(), " expression at " << (&v) << " eid = " << v->eid() << " while E_INTLIT=" << Expression::E_INTLIT ); // throw std::string("addLinConstr: only id's as variables allowed"); } MZN_MIPD__assert_hard( coefs.size()==vars.size() ); MZN_MIPD__assert_hard( CMPT_EQ==nCmpType || CMPT_LE==nCmpType ); DBGOUT_MIPD_SELF( // LinEq leq; leq.coefs=coefs; leq.vd=vars; leq.rhs=rhs; DBGOUT_MIPD__( " ADDING " << ( CMPT_EQ == nCmpType ? "LIN_EQ" : "LIN_LE" ) << ": [ " ); for ( auto c : coefs ) DBGOUT_MIPD__( c << ',' ); DBGOUT_MIPD__( " ] * [ " ); for ( auto v : vars ) { MZN_MIPD__assert_hard( !v->isa() ); if ( v->isa() ) DBGOUT_MIPD__( v->dyn_cast()->str() << ',' ); // else if ( v->isa() ) // MZN_MIPD__assert_hard ("addLinConstr: only id's as variables allowed"); else DBGOUT_MIPD__( mipd.expr2Const(v) << ',' ); } DBGOUT_MIPD( " ] " << ( CMPT_EQ == nCmpType ? "== " : "<= " ) << rhs ); ); std::vector nc_c; std::vector nx; bool fFloat = false; for ( auto v: vars ) { if ( !v->type().isint() ) { fFloat = true; break; } } auto sName = constants().ids.float_.lin_eq; // "int_lin_eq"; FunctionI* fDecl = mipd.float_lin_eq; if ( fFloat ) { // MZN_MIPD__assert_hard all vars of same type TODO for ( int i=0; i1e-8 ) /// Only add terms with non-0 coefs. TODO Eps=param { nc_c.push_back( FloatLit::a( coefs[i] ) ); if (vars[i]->type().isint()) { std::vector i2f_args(1); i2f_args[0] = vars[i]; Call* i2f = new Call(Location().introduce(),constants().ids.int2float,i2f_args); i2f->type(Type::varfloat()); i2f->decl(mipd.getEnv()->model()->matchFn(mipd.getEnv()->envi(), i2f, false)); EE ret = flat_exp(mipd.getEnv()->envi(), Ctx(), i2f, NULL, constants().var_true); nx.push_back( ret.r() ); } else { nx.push_back( vars[i] ); // ->id(); once passing a general expression } } args[2] = FloatLit::a(rhs); args[2]->type(Type::parfloat(0)); args[0] = new ArrayLit(Location().introduce(),nc_c); args[0]->type(Type::parfloat(1)); args[1] = new ArrayLit(Location().introduce(),nx); args[1]->type(Type::varfloat(1)); if ( CMPT_LE==nCmpType ) { sName = constants().ids.float_.lin_le; // "float_lin_le"; fDecl = mipd.float_lin_le; } } else { for ( int i=0; i1e-8 ) /// Only add terms with non-0 coefs. TODO Eps=param { nc_c.push_back( IntLit::a( static_cast(coefs[i]) ) ); nx.push_back( vars[i] ); //->id(); } args[2] = IntLit::a(static_cast(rhs)); args[2]->type(Type::parint(0)); args[0] = new ArrayLit(Location().introduce(),nc_c); args[0]->type(Type::parint(1)); args[1] = new ArrayLit(Location().introduce(),nx); args[1]->type(Type::varint(1)); if ( CMPT_LE==nCmpType ) { sName = constants().ids.int_.lin_le; // "int_lin_le"; fDecl = mipd.int_lin_le; } else { sName = constants().ids.int_.lin_eq; // "int_lin_eq"; fDecl = mipd.int_lin_eq; } } if ( mipd.getEnv()->envi().cse_map_end() != mipd.getEnv()->envi().cse_map_find( args[0] ) ) { DBGOUT_MIPD__( " Found expr " ); DBGOUT_MIPD_SELF( debugprint( args[0] ) ); } auto nc = new Call(Location().introduce(),ASTString(sName),args); nc->type(Type::varbool()); nc->decl(fDecl); mipd.getEnv()->envi().flat_addItem(new ConstraintI(Location().introduce(), nc)); } /// domain / reif set of one variable into that for a!her void convertIntSet( Expression* e, SetOfIntvReal& s, VarDecl* varTarget, double A, double B ) { MZN_MIPD__assert_hard( A != 0.0 ); if (e->type().isintset()) { IntSetVal* S = eval_intset( mipd.getEnv()->envi(), e ); IntSetRanges domr(S); for (; domr(); ++domr) { // * A + B IntVal mmin = domr.min(); IntVal mmax = domr.max(); if ( A < 0.0 ) std:: swap( mmin, mmax ); s.insert( IntvReal( // * A + B mmin.isFinite() ? rndUpIfInt( varTarget, (mmin.toInt() * A + B) ) : IntvReal::infMinus(), mmax.isFinite() ? rndDownIfInt( varTarget, (mmax.toInt() * A + B) ) : IntvReal::infPlus() ) ); } } else { assert(e->type().isfloatset()); FloatSetVal* S = eval_floatset( mipd.getEnv()->envi(), e ); FloatSetRanges domr(S); for (; domr(); ++domr) { // * A + B FloatVal mmin = domr.min(); FloatVal mmax = domr.max(); if ( A < 0.0 ) std:: swap( mmin, mmax ); s.insert( IntvReal( // * A + B mmin.isFinite() ? rndUpIfInt( varTarget, (mmin.toDouble() * A + B) ) : IntvReal::infMinus(), mmax.isFinite() ? rndDownIfInt( varTarget, (mmax.toDouble() * A + B) ) : IntvReal::infPlus() ) ); } } } /// compute the delta for float strict ineq double computeDelta( VarDecl* var, VarDecl* varOrig, IntvReal bnds, double A, Call* pCall, int nArg ) { double delta = varOrig->type().isfloat() ? mipd.expr2Const( pCall->arg(nArg) ) // * ( bnds.right-bnds.left ) ABANDONED 12.4.18 due to #207 : std::fabs( A ) ; // delta should be scaled as well if ( var->type().isint() ) // the projected-onto variable delta = std::max( 1.0, delta ); return delta; } }; // class DomainDecomp /// Vars without explicit clique still need a decomposition. /// Have !iced all __POSTs, set_in's && eq_encode's to it BEFORE /// In each clique, relate all vars to one chosen /// Find all "smallest rel. factor" variables, integer && with eq_encode if avail /// Re-relate all vars to it /// Refer all __POSTs && dom() to it /// build domain decomposition /// Implement all domain constraints, incl. possible corresp, of eq_encode's /// /// REMARKS. /// ! impose effects of integrality scaling (e.g., int v = int k/3) /// BUT when using k's eq_encode? /// And when subdividing into intervals bool decomposeDomains() { // for (int iClq=0; iClqremove(); if ( vVar.pEqEncoding ) vVar.pEqEncoding->remove(); } return fRetTrue; } VarDecl* expr2VarDecl(Expression* arg) { // The requirement to have actual variable objects // might be a limitation if more optimizations are done before... // Might need to flexibilize this TODO // MZN_MIPD__assert_hard_msg( ! arg->dyn_cast(), // "Expression " << *arg << " is an IntLit!" ); // MZN_MIPD__assert_hard( ! arg->dyn_cast() ); // MZN_MIPD__assert_hard( ! arg->dyn_cast() ); Id* id = arg->dyn_cast(); // MZN_MIPD__assert_hard(id); if ( nullptr==id ) return nullptr; // the call using this should be ignored? VarDecl* vd = id->decl(); MZN_MIPD__assert_hard(vd); return vd; } /// Fills the vector of vardecls && returns the least index of the array template long long expr2DeclArray(Expression* arg, Array& aVD) { ArrayLit* al = eval_array_lit(getEnv()->envi(), arg); checkOrResize( aVD, al->size() ); for (unsigned int i=0; isize(); i++) aVD[i] = expr2VarDecl((*al)[i]); return al->min(0); } /// Fills the vector of expressions && returns the least index of the array template long long expr2ExprArray(Expression* arg, Array& aVD) { ArrayLit* al = eval_array_lit(getEnv()->envi(), arg); checkOrResize( aVD, al->size() ); for (unsigned int i=0; isize(); i++) aVD[i] = ( (*al)[i] ); return al->min(0); } double expr2Const(Expression* arg) { if (IntLit* il = arg->dyn_cast()) { return ( static_cast(il->v().toInt()) ); } else if (FloatLit* fl = arg->dyn_cast()) { return ( fl->v().toDouble() ); } else if (BoolLit* bl = arg->dyn_cast()) { return ( bl->v() ); } else { MZN_MIPD__assert_hard_msg( 0, "unexpected expression instead of an int/float/bool literal: eid=" << arg->eid() << " while E_INTLIT=" << Expression::E_INTLIT ); } return 0.0; } template void checkOrResize(Container& cnt, size_t sz) { cnt.resize(sz); } template void checkOrResize(std::array& cnt, size_t sz) { MZN_MIPD__assert_hard( cnt.size() == sz ); } template void expr2Array(Expression* arg, Array& vals) { ArrayLit* al = eval_array_lit(getEnv()->envi(), arg); // if ( typeid(typename Array::pointer) == typeid(typename Array::iterator) ) // fixed array // MZN_MIPD__assert_hard( vals.size() == al->v().size() ); // else // vals.resize( al->v().size() ); checkOrResize(vals, al->size()); for (unsigned int i=0; isize(); i++) { vals[i] = expr2Const((*al)[i]); } } void printStats(std::ostream& os) { // if ( aCliques.empty() ) // return; if ( vVarDescr.empty() ) return; int nc=0; for ( auto& cl : aCliques ) if ( cl.size() ) ++nc; for ( auto& var : vVarDescr ) if ( 0>var.nClique ) ++nc; // 1-var cliques // os << "N cliques " << aCliques.size() << " total, " // << nc << " final" << std::endl; MZN_MIPD__assert_hard( nc ); MIPD__stats[ N_POSTs__eqNmapsize ] = static_cast(mNViews.size()); double nSubintvAve = MIPD__stats[ N_POSTs__NSubintvSum ] / nc; MZN_MIPD__assert_hard( MIPD__stats[ N_POSTs__NSubintvSum ] ); double dSubSizeAve = MIPD__stats[ N_POSTs__SubSizeSum ] / MIPD__stats[ N_POSTs__NSubintvSum ]; os << MIPD__stats[ N_POSTs__all ] << " POSTs" #ifdef __MZN__MIPDOMAINS__PRINTMORESTATS " [ " ; for ( int i=N_POSTs__intCmpReif; i<=N_POSTs__floatAux; ++i ) os << MIPD__stats[ i ] << ','; os << " ], LINEQ [ "; for ( int i=N_POSTs__eq2intlineq; i<=N_POSTs__eqNmapsize; ++i ) os << MIPD__stats[ i ] << ','; os << " ]" #endif ", " << MIPD__stats[ N_POSTs__varsDirect ] << " / " << MIPD__stats[ N_POSTs__varsInvolved ] << " vars, " << nc << " cliques, " << MIPD__stats[ N_POSTs__NSubintvMin ] << " / " << nSubintvAve << " / " << MIPD__stats[ N_POSTs__NSubintvMax ] << " NSubIntv m/a/m, " << MIPD__stats[ N_POSTs__SubSizeMin ] << " / " << dSubSizeAve << " / " << MIPD__stats[ N_POSTs__SubSizeMax ] << " SubIntvSize m/a/m, " << MIPD__stats[ N_POSTs__cliquesWithEqEncode ] << "+" << MIPD__stats[ N_POSTs__clEEEnforced ] << "(" << MIPD__stats[ N_POSTs__clEEFound ] << ")" << " clq eq_encoded "; // << std::flush if ( TCliqueSorter::LinEqGraph::dCoefMax > 1.0 ) os << TCliqueSorter::LinEqGraph::dCoefMin << "--" << TCliqueSorter::LinEqGraph::dCoefMax << " abs coefs"; os << " ... "; } }; // class MIPD template template void SetOfIntervals::intersect(const SetOfIntervals& s2) { if ( s2.empty() ) { this->clear(); return; } this->cutOut( Interval( Interval::infMinus(), (N)s2.begin()->left ) ); for ( auto is2=s2.begin(); is2!=s2.end(); ++is2 ) { auto is2next = is2; ++is2next; this->cutOut( Interval( is2->right, s2.end()==is2next ? Interval::infPlus() : (N)is2next->left ) ); } } template template void SetOfIntervals::cutDeltas( const SetOfIntervals& s2, N1 delta ) { if ( this->empty() ) return; // What if distance < delta? TODO for ( auto is2 : s2 ) { if ( is2.left > Interval::infMinus() ) this->cutOut( Interval( is2.left-delta, is2.left ) ); if ( is2.right < Interval::infPlus() ) this->cutOut( Interval( is2.right, is2.right+delta ) ); } } template void SetOfIntervals::cutOut(const Interval& intv) { DBGOUT_MIPD__( "Cutting " << intv << " from " << (*this) ); if ( this->empty() ) return; iterator it1 = ( Interval::infMinus() == intv.left ) ? this->lower_bound( Interval( intv.left, intv.right ) ) : this->upper_bound( Interval( intv.left, intv.right ) ); auto it2Del1 = it1; // from which to delete if ( this->begin() != it1 ) { --it1; const N it1l = it1->left; MZN_MIPD__assert_hard( it1l <= intv.left ); if ( it1->right > intv.left ) { // split it it2Del1 = split( it1, intv.left ).second; // it1->right = intv.left; READ-ONLY // this->erase(it1); // it1 = this->end(); // auto iR = this->insert( Interval( it1l, intv.left ) ); // MZN_MIPD__assert_hard( iR.second ); } } DBGOUT_MIPD__( "; after split 1: " << (*this) ); // Processing the right end: auto it2 = this->lower_bound( Interval( intv.right, intv.right+1 ) ); auto it2Del2 = it2; if ( this->begin() != it2 ) { --it2; MZN_MIPD__assert_hard( it2->left < intv.right ); const N it2r = it2->right; if ( ( Interval::infPlus() == intv.right ) ? ( it2r > intv.right ) : ( it2r >= intv.right ) ) { // >=: split it // it2Del2 = split( it2, intv.right ).second; const bool fEEE = (it2Del1 == it2); this->erase(it2); it2 = this->end(); it2Del2 = this->insert( Interval( intv.right, it2r ) ); if ( fEEE ) it2Del1 = it2Del2; } } DBGOUT_MIPD__( "; after split 2: " << (*this) ); DBGOUT_MIPD__( "; cutting out: " << SetOfIntervals(it2Del1, it2Del2) ); #ifdef MZN_DBG_CHECK_ITER_CUTOUT { auto it=this->begin(); int nO=0; do { if ( it==it2Del1 ) { MZN_MIPD__assert_hard( !nO ); ++ nO; } if ( it==it2Del2 ) { MZN_MIPD__assert_hard( 1==nO ); ++ nO; } if ( this->end()==it ) break; ++it; } while ( 1 ); MZN_MIPD__assert_hard( 2==nO ); } #endif this->erase( it2Del1, it2Del2 ); DBGOUT_MIPD( " ... gives " << (*this) ); } template typename SetOfIntervals::SplitResult SetOfIntervals::split(iterator& it, N pos) { MZN_MIPD__assert_hard( pos>=it->left ); MZN_MIPD__assert_hard( pos<=it->right ); Interval intvOld = *it; this->erase(it); iterator it_01 = this->insert( Interval ( intvOld.left, pos ) ); iterator it_02 = this->insert( Interval ( pos, intvOld.right ) ); it = this->end(); return std::make_pair( it_01, it_02 ); } template Interval SetOfIntervals::getBounds() const { if ( this->empty() ) return Interval( Interval::infPlus(), Interval::infMinus() ); iterator it2 = this->end(); --it2; return Interval( this->begin()->left, it2->right ); } template bool SetOfIntervals::checkFiniteBounds() { if ( this->empty() ) return false; auto bnds = getBounds(); return bnds.left > Interval::infMinus() && bnds.right < Interval::infPlus(); } template bool SetOfIntervals::checkDisjunctStrict() { for ( auto it=this->begin(); it!=this->end(); ++it ) { if ( it->left > it->right ) return false; if ( this->begin() != it ) { auto it_1 = it; --it_1; if ( it_1->right >= it->left ) return false; } } return true; } /// Assumes integer interval bounds template int SetOfIntervals::card_int() const { int nn=0; for (auto it=this->begin(); it!=this->end(); ++it) { ++nn; nn += int(round( it->right - it->left )); } return nn; } template N SetOfIntervals::max_interval() const { N ll=-1; for (auto it=this->begin(); it!=this->end(); ++it) { ll = std::max( ll, it->right - it->left ); } return ll; } /// Assumes integer interval bounds template void SetOfIntervals::split2Bits() { Base bsNew; for (auto it=this->begin(); it!=this->end(); ++it) { for (int v = static_cast(round( it->left )); v<=round( it->right ); ++v) bsNew.insert( Intv( v, v ) ); } *(Base*)this = std::move( bsNew ); } bool MIPD::fVerbose = false; void MIPdomains(Env& env, bool fVerbose, int nmi, double dmd) { MIPD mipd( &env, fVerbose, nmi, dmd ); if ( ! mipd.MIPdomains() ) { GCLock lock; env.envi().fail(); } } double MIPD::TCliqueSorter::LinEqGraph::dCoefMin = +1e100; double MIPD::TCliqueSorter::LinEqGraph::dCoefMax = -1e100; } // namespace MiniZinc libminizinc-2.4.2/lib/algorithms/000077500000000000000000000000001360574160400167535ustar00rootroot00000000000000libminizinc-2.4.2/lib/algorithms/min_cut.cpp000066400000000000000000000057251360574160400211260ustar00rootroot00000000000000#include #include #include #ifdef COMPILE_BOOST_MINCUT #include #include #include #include #include #include #endif void Algorithms::MinCut::solve() { #ifndef COMPILE_BOOST_MINCUT throw std::runtime_error( "MIP/circuit: Subtour Elimination Constraints: MinCut::solve not compiled. " "Compile with COMPILE_BOOST_MINCUT (needs boost), or use -D nSECcuts=0 for flattening." ); #else typedef std::pair< unsigned long, unsigned long > edge_t; // A graphic of the min-cut is available at using namespace std; typedef boost::adjacency_list > undirected_graph; typedef boost::property_map::type weight_map_type; typedef boost::property_traits::value_type weight_type; // define the 16 edges of the graph. {3, 4} means an undirected edge between vertices 3 and 4. // edge_t edges[] = {{3, 4}, {3, 6}, {3, 5}, {0, 4}, {0, 1}, {0, 6}, {0, 7}, // {0, 5}, {0, 2}, {4, 1}, {1, 6}, {1, 5}, {6, 7}, {7, 5}, {5, 2}, {3, 4}}; std::vector< edge_t > edges_array; // = edges; // std::vector< weight_type > ws_array; edges_array.reserve( edges.size() ); for ( const auto& edg: edges ) edges_array.push_back( std::pair( edg.first, edg.second ) ); // for each of the 16 edges, define the associated edge weight. ws[i] is the weight for the edge // that is described by edges[i]. // weight_type ws[] = {0.2, 3.1, 1.3, 3.7, 1.5, 2.6, 6.44, 1.26, 8.77, 1.29, 1.95, 80.74, 2.23, 1.94, 1.23, 4.957}; // construct the graph object. 8 is the number of vertices, which are numbered from 0 // through 7, and 16 is the number of edges. undirected_graph g(edges_array.data(), edges_array.data() + edges_array.size(), weights.data(), nNodes, edges_array.size()); // define a property map, `parities`, that will store a boolean value for each vertex. // Vertices that have the same parity after `stoer_wagner_min_cut` runs are on the same side of the min-cut. BOOST_AUTO(parities00, boost::make_one_bit_color_map(num_vertices(g), get(boost::vertex_index, g))); // run the Stoer-Wagner algorithm to obtain the min-cut weight. `parities` is also filled in. wMinCut = boost::stoer_wagner_min_cut(g, get(boost::edge_weight, g), boost::parity_map(parities00)); assert( nNodes==num_vertices(g) ); // parities = parities00; parities.clear(); parities.reserve( nNodes ); for (size_t i = 0; i < num_vertices(g); ++i) { parities.push_back (get(parities00, i)); } #endif } libminizinc-2.4.2/lib/ast.cpp000066400000000000000000002111271360574160400161010ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include #include #include namespace MiniZinc { Location::LocVec* Location::LocVec::a(const ASTString& filename, unsigned int first_line, unsigned int first_column, unsigned int last_line, unsigned int last_column) { static const unsigned int pointerBits = sizeof(IntLit*)*8; if (pointerBits<=32) { if (first_line < (1<<8) && last_line-first_line < (1<<7) && first_column < (1<<6) && last_column < (1<<7)) { long long int combined = first_line; combined |= (last_line-first_line)<<8; combined |= (first_column)<<(8+7); combined |= (last_column)<<(8+7+6); LocVec* v = static_cast(alloc(2)); new (v) LocVec(filename,combined); return v; } } else if (pointerBits>=64) { if (first_line < (1<<20) && last_line-first_line < (1<<20) && first_column < (1<<10) && last_column < (1<<10)) { long long int combined = first_line; combined |= (static_cast(last_line-first_line))<<20; combined |= (static_cast(first_column))<<(20+20); combined |= (static_cast(last_column))<<(20+20+10); LocVec* v = static_cast(alloc(2)); new (v) LocVec(filename,combined); return v; } } LocVec* v = static_cast(alloc(5)); new (v) LocVec(filename,first_line,first_column,last_line,last_column); return v; } Location::LocVec::LocVec(const ASTString& filename, IntVal combined) : ASTVec(2) { *(_data+0) = filename.aststr(); *(_data+1) = IntLit::a(combined); } Location::LocVec::LocVec(const ASTString& filename, unsigned int fl, unsigned int first_column, unsigned int last_line, unsigned int last_column) : ASTVec(5) { *(_data+0) = filename.aststr(); *(_data+1) = IntLit::a(fl); *(_data+2) = IntLit::a(last_line); *(_data+3) = IntLit::a(first_column); *(_data+4) = IntLit::a(last_column); } Location Location::nonalloc; Type Type::unboxedint = Type::parint(); Type Type::unboxedfloat = Type::parfloat(); Annotation Annotation::empty; std::string Location::toString(void) const { std::ostringstream oss; oss << filename() << ":" << first_line() << "." << first_column(); return oss.str(); } void Location::mark(void) const { if (lv()) lv()->mark(); } Location Location::introduce() const { Location l = *this; if (l._loc_info.lv) { l._loc_info.t |= 1; } return l; } void Expression::addAnnotation(Expression* ann) { if (!isUnboxedVal()) _ann.add(ann); } void Expression::addAnnotations(std::vector ann) { if (!isUnboxedVal()) for (unsigned int i=0; iisUnboxedVal()) return; std::vector stack; stack.reserve(1000); stack.push_back(e); while (!stack.empty()) { const Expression* cur = stack.back(); stack.pop_back(); if (!cur->isUnboxedVal() && cur->_gc_mark==0) { cur->_gc_mark = 1; cur->loc().mark(); pushann(cur->ann()); switch (cur->eid()) { case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_BOOLLIT: case Expression::E_ANON: break; case Expression::E_SETLIT: if (cur->cast()->isv()) { cur->cast()->isv()->mark(); } else if (cur->cast()->fsv()) { cur->cast()->fsv()->mark(); } else { pushall(cur->cast()->v()); } break; case Expression::E_STRINGLIT: cur->cast()->v().mark(); break; case Expression::E_ID: if (cur->cast()->idn()==-1) cur->cast()->v().mark(); pushstack(cur->cast()->decl()); break; case Expression::E_ARRAYLIT: if (cur->_flag_2) { pushstack(cur->cast()->_u._al); } else { pushall(ASTExprVec(cur->cast()->_u._v)); } cur->cast()->_dims.mark(); break; case Expression::E_ARRAYACCESS: pushstack(cur->cast()->v()); pushall(cur->cast()->idx()); break; case Expression::E_COMP: pushstack(cur->cast()->_e); pushall(cur->cast()->_g); cur->cast()->_g_idx.mark(); break; case Expression::E_ITE: pushstack(cur->cast()->e_else()); pushall(cur->cast()->_e_if_then); break; case Expression::E_BINOP: pushstack(cur->cast()->lhs()); pushstack(cur->cast()->rhs()); break; case Expression::E_UNOP: pushstack(cur->cast()->e()); break; case Expression::E_CALL: cur->cast()->id().mark(); for (unsigned int i=cur->cast()->n_args(); i--;) pushstack(cur->cast()->arg(i)); if (!cur->cast()->_u._oneArg->isUnboxedVal() && !cur->cast()->_u._oneArg->isTagged()) cur->cast()->_u._args->mark(); if (FunctionI* fi = cur->cast()->decl()) { fi->mark(); fi->id().mark(); pushstack(fi->ti()); pushann(fi->ann()); pushstack(fi->e()); pushall(fi->params()); } break; case Expression::E_VARDECL: pushstack(cur->cast()->ti()); pushstack(cur->cast()->e()); pushstack(cur->cast()->id()); break; case Expression::E_LET: pushall(cur->cast()->let()); pushall(cur->cast()->_let_orig); pushstack(cur->cast()->in()); break; case Expression::E_TI: pushstack(cur->cast()->domain()); pushall(cur->cast()->ranges()); break; case Expression::E_TIID: cur->cast()->v().mark(); break; } } } } #undef pushstack #undef pushall void IntLit::rehash(void) { init_hash(); std::hash h; cmb_hash(h(_v)); } void FloatLit::rehash(void) { init_hash(); std::hash h; cmb_hash(h(_v)); } void SetLit::rehash(void) { init_hash(); if (isv()) { std::hash h; for (IntSetRanges r0(isv()); r0(); ++r0) { cmb_hash(h(r0.min())); cmb_hash(h(r0.max())); } } else if (fsv()) { std::hash h; for (FloatSetRanges r0(fsv()); r0(); ++r0) { cmb_hash(h(r0.min())); cmb_hash(h(r0.max())); } } else { for (unsigned int i=v().size(); i--;) cmb_hash(Expression::hash(_v[i])); } } void BoolLit::rehash(void) { init_hash(); std::hash h; cmb_hash(h(_v)); } void StringLit::rehash(void) { init_hash(); cmb_hash(_v.hash()); } void Id::rehash(void) { init_hash(); std::hash h; if (idn()==-1) cmb_hash(v().hash()); else cmb_hash(h(idn())); } ASTString Id::str() const { if (idn()==-1) return v(); std::ostringstream oss; oss << "X_INTRODUCED_" << idn() << "_"; return oss.str(); } void TIId::rehash(void) { init_hash(); cmb_hash(_v.hash()); } void AnonVar::rehash(void) { init_hash(); } int ArrayLit::dims(void) const { return _flag_2 ? ( (_dims.size() - 2*_u._al->dims()) / 2 ) : (_dims.size()==0 ? 1 : _dims.size()/2); } int ArrayLit::min(int i) const { if (_dims.size()==0) { assert(i==0); return 1; } return _dims[2*i]; } int ArrayLit::max(int i) const { if (_dims.size()==0) { assert(i==0); return _u._v->size(); } return _dims[2*i+1]; } int ArrayLit::length(void) const { if(dims() == 0) return 0; int l = max(0) - min(0) + 1; for(int i=1; i d(2+_u._al->dims()*2); int dimOffset = dims()*2; d[0] = 1; d[1] = length(); for (unsigned int i=2; i d(2); d[0] = 1; d[1] = length(); _dims = ASTIntVec(d); } } } int ArrayLit::origIdx(int i) const { assert(_flag_2); int curIdx = i; int multiplyer = 1; int oIdx = 0; int sliceOffset = dims()*2; for (int curDim = _u._al->dims()-1; curDim >= 0; curDim--) { oIdx += multiplyer * ( ( curIdx % (_dims[sliceOffset+curDim*2+1]-_dims[sliceOffset+curDim*2]+1) ) + (_dims[sliceOffset+curDim*2] - _u._al->min(curDim)) ); curIdx = curIdx / (_dims[sliceOffset+curDim*2+1]-_dims[sliceOffset+curDim*2]+1); multiplyer *= (_u._al->max(curDim)-_u._al->min(curDim)+1); } return oIdx; } Expression* ArrayLit::slice_get(int i) const { if (!_flag_2) { assert(_u._v->flag()); int off = length()-_u._v->size(); return i <= off ? (*_u._v)[0] : (*_u._v)[i-off]; } else { assert(_flag_2); return (*_u._al)[origIdx(i)]; } } void ArrayLit::slice_set(int i, Expression* e) { if (!_flag_2) { assert(_u._v->flag()); int off = length()-_u._v->size(); if (i <= off) { (*_u._v)[0] = e; } else { (*_u._v)[i-off] = e; } } else { assert(_flag_2); _u._al->set(origIdx(i), e); } } ArrayLit::ArrayLit(const Location& loc, ArrayLit* v, const std::vector >& dims, const std::vector >& slice) : Expression(loc,E_ARRAYLIT,Type()) { _flag_1 = false; _flag_2 = true; _u._al = v; assert(slice.size() == v->dims()); std::vector d(dims.size()*2+2*slice.size()); for (unsigned int i=static_cast(dims.size()); i--;) { d[i*2 ] = dims[i].first; d[i*2+1] = dims[i].second; } int sliceOffset = static_cast(2*dims.size()); for (unsigned int i=static_cast(slice.size()); i--;) { d[sliceOffset+i*2 ] = slice[i].first; d[sliceOffset+i*2+1] = slice[i].second; } _dims = ASTIntVec(d); } void ArrayLit::compress(const std::vector& v, const std::vector& dims) { if (v.size() >= 4 && Expression::equal(v[0], v[1]) && Expression::equal(v[1], v[2]) && Expression::equal(v[2], v[3])) { std::vector compress(v.size()); compress[0] = v[0]; int k = 4; while (k(compress).vec(); _u._v->flag(true); _dims = ASTIntVec(dims); } else { _u._v = ASTExprVec(v).vec(); if (dims.size()!=2 || dims[0]!=1) { // only allocate dims vector if it is not a 1d array indexed from 1 _dims = ASTIntVec(dims); } } } ArrayLit::ArrayLit(const Location& loc, const std::vector& v, const std::vector >& dims) : Expression(loc,E_ARRAYLIT,Type()) { _flag_1 = false; _flag_2 = false; std::vector d(dims.size()*2); for (unsigned int i=static_cast(dims.size()); i--;) { d[i*2] = dims[i].first; d[i*2+1] = dims[i].second; } compress(v, d); rehash(); } void ArrayLit::rehash(void) { init_hash(); std::hash h; for (unsigned int i=0; i<_dims.size(); i++) { cmb_hash(h(_dims[i])); } if (_flag_2) { cmb_hash(Expression::hash(_u._al)); } else { for (unsigned int i=_u._v->size(); i--;) { cmb_hash(h(i)); cmb_hash(Expression::hash((*_u._v)[i])); } } } void ArrayAccess::rehash(void) { init_hash(); cmb_hash(Expression::hash(_v)); std::hash h; cmb_hash(h(_idx.size())); for (unsigned int i=_idx.size(); i--;) cmb_hash(Expression::hash(_idx[i])); } Generator::Generator(const std::vector& v, Expression* in, Expression* where) { std::vector vd; Location loc = in == NULL ? where->loc() : in->loc(); for (unsigned int i=0; itoplevel(false); vd.push_back(nvd); } _v = vd; _in = in; _where = where; } Generator::Generator(const std::vector& v, Expression* in, Expression* where) { std::vector vd; for (unsigned int i=0; iloc(), new TypeInst(v[i]->loc(),Type::parint()),v[i]->v()); nvd->toplevel(false); vd.push_back(nvd); } _v = vd; _in = in; _where = where; } Generator::Generator(const std::vector& v, Expression* in, Expression* where) { std::vector vd; Location loc = in == NULL ? where->loc() : in->loc(); for (unsigned int i=0; itoplevel(false); vd.push_back(nvd); } _v = vd; _in = in; _where = where; } Generator::Generator(const std::vector& v, Expression* in, Expression* where) { _v = v; _in = in; _where = where; } Generator::Generator(int pos, Expression* where) { std::vector vd; std::ostringstream oss; oss << "__dummy" << pos; VarDecl* nvd = new VarDecl(Location().introduce(), new TypeInst(Location().introduce(),Type::parint()),ASTString(oss.str())); nvd->toplevel(false); vd.push_back(nvd); _v = vd; _in = new ArrayLit(Location().introduce(), std::vector({IntLit::a(0)})); _where = where; } bool Comprehension::set(void) const { return _flag_1; } void Comprehension::rehash(void) { init_hash(); std::hash h; cmb_hash(h(set())); cmb_hash(Expression::hash(_e)); cmb_hash(h(_g_idx.size())); for (unsigned int i=_g_idx.size(); i--;) { cmb_hash(h(_g_idx[i])); } cmb_hash(h(_g.size())); for (unsigned int i=_g.size(); i--;) { cmb_hash(Expression::hash(_g[i])); } } int Comprehension::n_generators(void) const { return _g_idx.size()-1; } Expression* Comprehension::in(int i) { return _g[_g_idx[i]]; } const Expression* Comprehension::in(int i) const { return _g[_g_idx[i]]; } const Expression* Comprehension::where(int i) const { return _g[_g_idx[i]+1]; } Expression* Comprehension::where(int i) { return _g[_g_idx[i]+1]; } int Comprehension::n_decls(int i) const { return _g_idx[i+1]-_g_idx[i]-2; } VarDecl* Comprehension::decl(int gen, int i) { return _g[_g_idx[gen]+2+i]->cast(); } const VarDecl* Comprehension::decl(int gen, int i) const { return _g[_g_idx[gen]+2+i]->cast(); } bool Comprehension::containsBoundVariable(Expression* e) { std::unordered_set decls; for (unsigned int i=0; i& _decls; bool _found; public: FindVar(std::unordered_set& decls) : _decls(decls), _found(false) {} bool enter(Expression*) { return !_found; } void vId(Id& ident) { if (_decls.find(ident.decl()) != _decls.end()) { _found = true; } } bool found(void) const { return _found; } } _fv(decls); topDown(_fv, e); return _fv.found(); } void ITE::rehash(void) { init_hash(); std::hash h; cmb_hash(h(_e_if_then.size())); for (unsigned int i=_e_if_then.size(); i--; ) { cmb_hash(Expression::hash(_e_if_then[i])); } cmb_hash(Expression::hash(e_else())); } BinOpType BinOp::op(void) const { return static_cast(_sec_id); } void BinOp::rehash(void) { init_hash(); std::hash h; cmb_hash(h(static_cast(op()))); cmb_hash(Expression::hash(_e0)); cmb_hash(Expression::hash(_e1)); } Call* BinOp::morph(const ASTString& ident, const std::vector& args) { _id = Call::eid; _flag_1 = true; Call* c = cast(); c->id(ident); c->args(args); return c; } namespace { class OpToString { protected: Model* rootSetModel; public: Id* sBOT_PLUS; Id* sBOT_MINUS; Id* sBOT_MULT; Id* sBOT_DIV; Id* sBOT_IDIV; Id* sBOT_MOD; Id* sBOT_POW; Id* sBOT_LE; Id* sBOT_LQ; Id* sBOT_GR; Id* sBOT_GQ; Id* sBOT_EQ; Id* sBOT_NQ; Id* sBOT_IN; Id* sBOT_SUBSET; Id* sBOT_SUPERSET; Id* sBOT_UNION; Id* sBOT_DIFF; Id* sBOT_SYMDIFF; Id* sBOT_INTERSECT; Id* sBOT_PLUSPLUS; Id* sBOT_EQUIV; Id* sBOT_IMPL; Id* sBOT_RIMPL; Id* sBOT_OR; Id* sBOT_AND; Id* sBOT_XOR; Id* sBOT_DOTDOT; Id* sBOT_NOT; OpToString(void) { GCLock lock; rootSetModel = new Model(); std::vector rootSet; sBOT_PLUS = new Id(Location(),"'+'",NULL); rootSet.push_back(sBOT_PLUS); sBOT_MINUS = new Id(Location(),"'-'",NULL); rootSet.push_back(sBOT_MINUS); sBOT_MULT = new Id(Location(),"'*'",NULL); rootSet.push_back(sBOT_MULT); sBOT_DIV = new Id(Location(),"'/'",NULL); rootSet.push_back(sBOT_DIV); sBOT_IDIV = new Id(Location(),"'div'",NULL); rootSet.push_back(sBOT_IDIV); sBOT_MOD = new Id(Location(),"'mod'",NULL); rootSet.push_back(sBOT_MOD); sBOT_POW = new Id(Location(),"'^'",NULL); rootSet.push_back(sBOT_POW); sBOT_LE = new Id(Location(),"'<'",NULL); rootSet.push_back(sBOT_LE); sBOT_LQ = new Id(Location(),"'<='",NULL); rootSet.push_back(sBOT_LQ); sBOT_GR = new Id(Location(),"'>'",NULL); rootSet.push_back(sBOT_GR); sBOT_GQ = new Id(Location(),"'>='",NULL); rootSet.push_back(sBOT_GQ); sBOT_EQ = new Id(Location(),"'='",NULL); rootSet.push_back(sBOT_EQ); sBOT_NQ = new Id(Location(),"'!='",NULL); rootSet.push_back(sBOT_NQ); sBOT_IN = new Id(Location(),"'in'",NULL); rootSet.push_back(sBOT_IN); sBOT_SUBSET = new Id(Location(),"'subset'",NULL); rootSet.push_back(sBOT_SUBSET); sBOT_SUPERSET = new Id(Location(),"'superset'",NULL); rootSet.push_back(sBOT_SUPERSET); sBOT_UNION = new Id(Location(),"'union'",NULL); rootSet.push_back(sBOT_UNION); sBOT_DIFF = new Id(Location(),"'diff'",NULL); rootSet.push_back(sBOT_DIFF); sBOT_SYMDIFF = new Id(Location(),"'symdiff'",NULL); rootSet.push_back(sBOT_SYMDIFF); sBOT_INTERSECT = new Id(Location(),"'intersect'",NULL); rootSet.push_back(sBOT_INTERSECT); sBOT_PLUSPLUS = new Id(Location(),"'++'",NULL); rootSet.push_back(sBOT_PLUSPLUS); sBOT_EQUIV = new Id(Location(),"'<->'",NULL); rootSet.push_back(sBOT_EQUIV); sBOT_IMPL = new Id(Location(),"'->'",NULL); rootSet.push_back(sBOT_IMPL); sBOT_RIMPL = new Id(Location(),"'<-'",NULL); rootSet.push_back(sBOT_RIMPL); sBOT_OR = new Id(Location(),"'\\/'",NULL); rootSet.push_back(sBOT_OR); sBOT_AND = new Id(Location(),"'/\\'",NULL); rootSet.push_back(sBOT_AND); sBOT_XOR = new Id(Location(),"'xor'",NULL); rootSet.push_back(sBOT_XOR); sBOT_DOTDOT = new Id(Location(),"'..'",NULL); rootSet.push_back(sBOT_DOTDOT); sBOT_NOT = new Id(Location(),"'not'",NULL); rootSet.push_back(sBOT_NOT); rootSetModel->addItem(new ConstraintI(Location(), new ArrayLit(Location(),rootSet))); } static OpToString& o(void) { static OpToString _o; return _o; } }; } ASTString BinOp::opToString(void) const { switch (op()) { case BOT_PLUS: return OpToString::o().sBOT_PLUS->v(); case BOT_MINUS: return OpToString::o().sBOT_MINUS->v(); case BOT_MULT: return OpToString::o().sBOT_MULT->v(); case BOT_DIV: return OpToString::o().sBOT_DIV->v(); case BOT_IDIV: return OpToString::o().sBOT_IDIV->v(); case BOT_MOD: return OpToString::o().sBOT_MOD->v(); case BOT_POW: return OpToString::o().sBOT_POW->v(); case BOT_LE: return OpToString::o().sBOT_LE->v(); case BOT_LQ: return OpToString::o().sBOT_LQ->v(); case BOT_GR: return OpToString::o().sBOT_GR->v(); case BOT_GQ: return OpToString::o().sBOT_GQ->v(); case BOT_EQ: return OpToString::o().sBOT_EQ->v(); case BOT_NQ: return OpToString::o().sBOT_NQ->v(); case BOT_IN: return OpToString::o().sBOT_IN->v(); case BOT_SUBSET: return OpToString::o().sBOT_SUBSET->v(); case BOT_SUPERSET: return OpToString::o().sBOT_SUPERSET->v(); case BOT_UNION: return OpToString::o().sBOT_UNION->v(); case BOT_DIFF: return OpToString::o().sBOT_DIFF->v(); case BOT_SYMDIFF: return OpToString::o().sBOT_SYMDIFF->v(); case BOT_INTERSECT: return OpToString::o().sBOT_INTERSECT->v(); case BOT_PLUSPLUS: return OpToString::o().sBOT_PLUSPLUS->v(); case BOT_EQUIV: return OpToString::o().sBOT_EQUIV->v(); case BOT_IMPL: return OpToString::o().sBOT_IMPL->v(); case BOT_RIMPL: return OpToString::o().sBOT_RIMPL->v(); case BOT_OR: return OpToString::o().sBOT_OR->v(); case BOT_AND: return OpToString::o().sBOT_AND->v(); case BOT_XOR: return OpToString::o().sBOT_XOR->v(); case BOT_DOTDOT: return OpToString::o().sBOT_DOTDOT->v(); default: assert(false); return ASTString(""); } } UnOpType UnOp::op(void) const { return static_cast(_sec_id); } void UnOp::rehash(void) { init_hash(); std::hash h; cmb_hash(h(static_cast(_sec_id))); cmb_hash(Expression::hash(_e0)); } ASTString UnOp::opToString(void) const { switch (op()) { case UOT_PLUS: return OpToString::o().sBOT_PLUS->v(); case UOT_MINUS: return OpToString::o().sBOT_MINUS->v(); case UOT_NOT: return OpToString::o().sBOT_NOT->v(); default: assert(false); return ASTString(""); } } void Call::rehash(void) { init_hash(); cmb_hash(id().hash()); std::hash hf; cmb_hash(hf(decl())); std::hash hu; cmb_hash(hu(n_args())); for (unsigned int i=0; iranges().size() > 0) { GC::trail(reinterpret_cast(&_ti),_ti); } } void VarDecl::rehash(void) { init_hash(); cmb_hash(Expression::hash(_ti)); cmb_hash(_id->hash()); cmb_hash(Expression::hash(_e)); } void Let::rehash(void) { init_hash(); cmb_hash(Expression::hash(_in)); std::hash h; cmb_hash(h(_let.size())); for (unsigned int i=_let.size(); i--;) cmb_hash(Expression::hash(_let[i])); } Let::Let(const Location& loc, const std::vector& let, Expression* in) : Expression(loc,E_LET,Type()) { _let = ASTExprVec(let); std::vector vde; for (unsigned int i=0; i(let[i])) { vde.push_back(vd->e()); for (unsigned int i=0; iti()->ranges().size(); i++) { vde.push_back(vd->ti()->ranges()[i]->domain()); } } } _let_orig = ASTExprVec(vde); _in = in; rehash(); } void Let::pushbindings(void) { GC::mark(); for (unsigned int i=0, j=0; i<_let.size(); i++) { if (VarDecl* vd = _let[i]->dyn_cast()) { vd->trail(); vd->e(_let_orig[j++]); for (unsigned int k=0; kti()->ranges().size(); k++) { vd->ti()->ranges()[k]->domain(_let_orig[j++]); } } } } void Let::popbindings(void) { for (unsigned int i=0; i<_let.size(); i++) { if (VarDecl* vd = _let[i]->dyn_cast()) { GC::untrail(); break; } } } void TypeInst::rehash(void) { init_hash(); std::hash h; unsigned int rsize = _ranges.size(); cmb_hash(h(rsize)); for (unsigned int i=rsize; i--;) cmb_hash(Expression::hash(_ranges[i])); cmb_hash(Expression::hash(domain())); } void TypeInst::setRanges(const std::vector& ranges) { _ranges = ASTExprVec(ranges); if (ranges.size()==1 && ranges[0] && ranges[0]->isa() && ranges[0]->cast()->domain() && ranges[0]->cast()->domain()->isa() && !ranges[0]->cast()->domain()->cast()->v().beginsWith("$")) _type.dim(-1); else _type.dim(static_cast(ranges.size())); rehash(); } bool TypeInst::hasTiVariable(void) const { if (domain() && domain()->isa()) return true; for (unsigned int i=_ranges.size(); i--;) if (_ranges[i]->isa()) return true; return false; } namespace { Type getType(Expression* e) { return e->type(); } Type getType(const Type& t) { return t; } const Location& getLoc(Expression* e, FunctionI*) { return e->loc(); } const Location& getLoc(const Type&, FunctionI* fi) { return fi->loc(); } bool isaTIId(Expression* e) { if (TIId* t = Expression::dyn_cast(e)) { return !t->v().beginsWith("$"); } return false; } bool isaEnumTIId(Expression* e) { if (TIId* t = Expression::dyn_cast(e)) { return t->v().beginsWith("$"); } return false; } template Type return_type(EnvI& env, FunctionI* fi, const std::vector& ta, bool strictEnum) { if (fi->id()==constants().var_redef->id()) return Type::varbool(); Type ret = fi->ti()->type(); ASTString dh; if (fi->ti()->domain() && fi->ti()->domain()->isa()) dh = fi->ti()->domain()->cast()->v(); ASTString rh; if (fi->ti()->ranges().size()==1 && isaTIId(fi->ti()->ranges()[0]->domain())) rh = fi->ti()->ranges()[0]->domain()->cast()->v(); ASTStringMap::t tmap; for (unsigned int i=0; iparams()[i]->ti(); if (tii->domain() && tii->domain()->isa()) { ASTString tiid = tii->domain()->cast()->v(); Type tiit = getType(ta[i]); if (tiit.enumId() != 0 && tiit.dim() > 0) { const std::vector& enumIds = env.getArrayEnum(tiit.enumId()); tiit.enumId(enumIds[enumIds.size()-1]); } tiit.dim(0); if (tii->type().st()==Type::ST_SET) { tiit.st(Type::ST_PLAIN); } if (isaEnumTIId(tii->domain())) { tiit.st(Type::ST_SET); } ASTStringMap::t::iterator it = tmap.find(tiid); if (it==tmap.end()) { tmap.insert(std::pair(tiid,tiit)); } else { if (it->second.dim() > 0) { throw TypeError(env, getLoc(ta[i],fi),"type-inst variable $"+ tiid.str()+" used in both array and non-array position"); } else { Type tiit_par = tiit; tiit_par.ti(Type::TI_PAR); tiit_par.ot(Type::OT_PRESENT); Type its_par = it->second; its_par.ti(Type::TI_PAR); its_par.ot(Type::OT_PRESENT); if (tiit_par.bt()==Type::BT_TOP || tiit_par.bt()==Type::BT_BOT) { tiit_par.bt(its_par.bt()); } if (its_par.bt()==Type::BT_TOP || its_par.bt()==Type::BT_BOT) { its_par.bt(tiit_par.bt()); } if (env.isSubtype(tiit_par,its_par,strictEnum)) { if (it->second.bt() == Type::BT_TOP) it->second.bt(tiit.bt()); } else if (env.isSubtype(its_par,tiit_par,strictEnum)) { it->second = tiit_par; } else { throw TypeError(env, getLoc(ta[i],fi),"type-inst variable $"+ tiid.str()+" instantiated with different types ("+ tiit.toString(env)+" vs "+ it->second.toString(env)+")"); } } } } if (tii->ranges().size()==1 && isaTIId(tii->ranges()[0]->domain())) { ASTString tiid = tii->ranges()[0]->domain()->cast()->v(); Type orig_tiit = getType(ta[i]); if (orig_tiit.dim()==0) { throw TypeError(env, getLoc(ta[i],fi),"type-inst variable $"+tiid.str()+ " must be an array index"); } Type tiit = Type::top(orig_tiit.dim()); if (orig_tiit.enumId() != 0) { std::vector enumIds(tiit.dim()+1); const std::vector& orig_enumIds = env.getArrayEnum(orig_tiit.enumId()); for (unsigned int i=0; i::t::iterator it = tmap.find(tiid); if (it==tmap.end()) { tmap.insert(std::pair(tiid,tiit)); } else { if (it->second.dim() == 0) { throw TypeError(env, getLoc(ta[i],fi),"type-inst variable $"+ tiid.str()+" used in both array and non-array position"); } else if (it->second!=tiit) { throw TypeError(env, getLoc(ta[i],fi),"type-inst variable $"+ tiid.str()+" instantiated with different types ("+ tiit.toString(env)+" vs "+ it->second.toString(env)+")"); } } } else if (tii->ranges().size() > 0) { for (unsigned int j=0; jranges().size(); j++) { if (isaEnumTIId(tii->ranges()[j]->domain())) { ASTString enumTIId = tii->ranges()[j]->domain()->cast()->v(); Type tiit = getType(ta[i]); Type enumIdT; if (tiit.enumId() != 0) { unsigned int enumId = env.getArrayEnum(tiit.enumId())[j]; enumIdT = Type::parsetenum(enumId); } else { enumIdT = Type::parsetint(); } ASTStringMap::t::iterator it = tmap.find(enumTIId); // TODO: this may clash if the same enum TIId is used for different types // but the same enum if (it==tmap.end()) { tmap.insert(std::pair(enumTIId,enumIdT)); } else { if (it->second.enumId() != enumIdT.enumId()) { throw TypeError(env, getLoc(ta[i],fi),"type-inst variable $"+ enumTIId.str()+" used for different enum types"); } } } } } } if (dh.size() != 0) { ASTStringMap::t::iterator it = tmap.find(dh); if (it==tmap.end()) throw TypeError(env, fi->loc(),"type-inst variable $"+dh.str()+" used but not defined"); if (dh.beginsWith("$")) { // this is an enum ret.bt(Type::BT_INT); } else { ret.bt(it->second.bt()); if (ret.st()==Type::ST_PLAIN) ret.st(it->second.st()); } if (fi->ti()->ranges().size() > 0 && it->second.enumId() != 0) { std::vector enumIds(fi->ti()->ranges().size()+1); for (unsigned int i=0; iti()->ranges().size(); i++) { enumIds[i] = 0; } enumIds[enumIds.size()-1] = it->second.enumId(); ret.enumId(env.registerArrayEnum(enumIds)); } else { ret.enumId(it->second.enumId()); } } if (rh.size() != 0) { ASTStringMap::t::iterator it = tmap.find(rh); if (it==tmap.end()) throw TypeError(env, fi->loc(),"type-inst variable $"+rh.str()+" used but not defined"); ret.dim(it->second.dim()); if (it->second.enumId() != 0) { std::vector enumIds(it->second.dim()+1); const std::vector& orig_enumIds = env.getArrayEnum(it->second.enumId()); for (unsigned int i=0; iti()->ranges().size() > 0) { std::vector enumIds(fi->ti()->ranges().size()+1); bool hadRealEnum = false; if (ret.enumId()==0) { enumIds[enumIds.size()-1] = 0; } else { enumIds[enumIds.size()-1] = env.getArrayEnum(ret.enumId())[enumIds.size()-1]; hadRealEnum = true; } for (unsigned int i=0; iti()->ranges().size(); i++) { if (isaEnumTIId(fi->ti()->ranges()[i]->domain())) { ASTString enumTIId = fi->ti()->ranges()[i]->domain()->cast()->v(); ASTStringMap::t::iterator it = tmap.find(enumTIId); if (it==tmap.end()) throw TypeError(env, fi->loc(),"type-inst variable $"+enumTIId.str()+" used but not defined"); enumIds[i] = it->second.enumId(); hadRealEnum |= (enumIds[i] != 0); } else { enumIds[i] = 0; } } if (hadRealEnum) ret.enumId(env.registerArrayEnum(enumIds)); } return ret; } } Type FunctionI::rtype(EnvI& env, const std::vector& ta, bool strictEnums) { return return_type(env, this, ta, strictEnums); } Type FunctionI::rtype(EnvI& env, const std::vector& ta, bool strictEnums) { return return_type(env, this, ta, strictEnums); } Type FunctionI::argtype(EnvI& env, const std::vector& ta, int n) { TypeInst* tii = params()[n]->ti(); if (tii->domain() && tii->domain()->isa()) { Type ty = ta[n]->type(); ty.st(tii->type().st()); ty.dim(tii->type().dim()); ASTString tv = tii->domain()->cast()->v(); for (unsigned int i=0; iti()->domain() && params()[i]->ti()->domain()->isa() && params()[i]->ti()->domain()->cast()->v() == tv) { Type toCheck = ta[i]->type(); toCheck.st(tii->type().st()); toCheck.dim(tii->type().dim()); if (toCheck != ty) { if (env.isSubtype(ty,toCheck,true)) { ty = toCheck; } else { Type ty_par = ty; ty_par.ti(Type::TI_PAR); Type toCheck_par = toCheck; toCheck_par.ti(Type::TI_PAR); if (env.isSubtype(ty_par,toCheck_par,true)) { ty.bt(toCheck.bt()); } } } } } return ty; } else { return tii->type(); } } bool Expression::equal_internal(const Expression* e0, const Expression* e1) { switch (e0->eid()) { case Expression::E_INTLIT: return e0->cast()->v() == e1->cast()->v(); case Expression::E_FLOATLIT: return e0->cast()->v() == e1->cast()->v(); case Expression::E_SETLIT: { const SetLit* s0 = e0->cast(); const SetLit* s1 = e1->cast(); if (s0->isv()) { if (s1->isv()) { IntSetRanges r0(s0->isv()); IntSetRanges r1(s1->isv()); return Ranges::equal(r0,r1); } else { return false; } } else if (s0->fsv()) { if (s1->fsv()) { FloatSetRanges r0(s0->fsv()); FloatSetRanges r1(s1->fsv()); return Ranges::equal(r0,r1); } else { return false; } } else { if (s1->isv() || s1->fsv()) return false; if (s0->v().size() != s1->v().size()) return false; for (unsigned int i=0; iv().size(); i++) if (!Expression::equal( s0->v()[i], s1->v()[i] )) return false; return true; } } case Expression::E_BOOLLIT: return e0->cast()->v() == e1->cast()->v(); case Expression::E_STRINGLIT: return e0->cast()->v() == e1->cast()->v(); case Expression::E_ID: { const Id* id0 = e0->cast(); const Id* id1 = e1->cast(); if (id0->decl()==NULL || id1->decl()==NULL) { return id0->v()==id1->v() && id0->idn()==id1->idn(); } return id0->decl()==id1->decl() || ( id0->decl()->flat() != NULL && id0->decl()->flat() == id1->decl()->flat() ); } case Expression::E_ANON: return false; case Expression::E_ARRAYLIT: { const ArrayLit* a0 = e0->cast(); const ArrayLit* a1 = e1->cast(); if (a0->size() != a1->size()) return false; if (a0->_dims.size() != a1->_dims.size()) return false; for (unsigned int i=0; i_dims.size(); i++) { if ( a0->_dims[i] != a1->_dims[i] ) { return false; } } for (unsigned int i=0; isize(); i++) { if (!Expression::equal( (*a0)[i], (*a1)[i] )) { return false; } } return true; } case Expression::E_ARRAYACCESS: { const ArrayAccess* a0 = e0->cast(); const ArrayAccess* a1 = e1->cast(); if (!Expression::equal( a0->v(), a1->v() )) return false; if (a0->idx().size() != a1->idx().size()) return false; for (unsigned int i=0; iidx().size(); i++) if (!Expression::equal( a0->idx()[i], a1->idx()[i] )) return false; return true; } case Expression::E_COMP: { const Comprehension* c0 = e0->cast(); const Comprehension* c1 = e1->cast(); if (c0->set() != c1->set()) return false; if (!Expression::equal ( c0->_e, c1->_e )) return false; if (c0->_g.size() != c1->_g.size()) return false; for (unsigned int i=0; i_g.size(); i++) { if (!Expression::equal( c0->_g[i], c1->_g[i] )) return false; } for (unsigned int i=0; i_g_idx.size(); i++) { if (c0->_g_idx[i] != c1->_g_idx[i]) return false; } return true; } case Expression::E_ITE: { const ITE* i0 = e0->cast(); const ITE* i1 = e1->cast(); if (i0->_e_if_then.size() != i1->_e_if_then.size()) return false; for (unsigned int i=i0->_e_if_then.size(); i--; ) { if (!Expression::equal ( i0->_e_if_then[i], i1->_e_if_then[i])) return false; } if (!Expression::equal (i0->e_else(), i1->e_else())) return false; return true; } case Expression::E_BINOP: { const BinOp* b0 = e0->cast(); const BinOp* b1 = e1->cast(); if (b0->op() != b1->op()) return false; if (!Expression::equal (b0->lhs(), b1->lhs())) return false; if (!Expression::equal (b0->rhs(), b1->rhs())) return false; return true; } case Expression::E_UNOP: { const UnOp* b0 = e0->cast(); const UnOp* b1 = e1->cast(); if (b0->op() != b1->op()) return false; if (!Expression::equal (b0->e(), b1->e())) return false; return true; } case Expression::E_CALL: { const Call* c0 = e0->cast(); const Call* c1 = e1->cast(); if (c0->id() != c1->id()) return false; if (c0->decl() != c1->decl()) return false; if (c0->n_args() != c1->n_args()) return false; for (unsigned int i=0; in_args(); i++) if (!Expression::equal ( c0->arg(i), c1->arg(i) )) return false; return true; } case Expression::E_VARDECL: { const VarDecl* v0 = e0->cast(); const VarDecl* v1 = e1->cast(); if (!Expression::equal ( v0->ti(), v1->ti() )) return false; if (!Expression::equal ( v0->id(), v1->id())) return false; if (!Expression::equal ( v0->e(), v1->e() )) return false; return true; } case Expression::E_LET: { const Let* l0 = e0->cast(); const Let* l1 = e1->cast(); if (!Expression::equal ( l0->in(), l1->in() )) return false; if (l0->let().size() != l1->let().size()) return false; for (unsigned int i=l0->let().size(); i--;) if (!Expression::equal ( l0->let()[i], l1->let()[i])) return false; return true; } case Expression::E_TI: { const TypeInst* t0 = e0->cast(); const TypeInst* t1 = e1->cast(); if (t0->ranges().size() != t1->ranges().size()) return false; for (unsigned int i=t0->ranges().size(); i--;) if (!Expression::equal ( t0->ranges()[i], t1->ranges()[i])) return false; if (!Expression::equal (t0->domain(), t1->domain())) return false; return true; } case Expression::E_TIID: return false; default: assert(false); return false; } } Constants::Constants(void) { GCLock lock; TypeInst* ti = new TypeInst(Location(), Type::parbool()); lit_true = new BoolLit(Location(), true); var_true = new VarDecl(Location(), ti, "_bool_true", lit_true); lit_false = new BoolLit(Location(), false); var_false = new VarDecl(Location(), ti, "_bool_false", lit_false); var_ignore = new VarDecl(Location(), ti, "_bool_ignore"); absent = new Id(Location(),"_absent",NULL); Type absent_t; absent_t.bt(Type::BT_BOT); absent_t.dim(0); absent_t.st(Type::ST_PLAIN); absent_t.ot(Type::OT_OPTIONAL); absent->type(absent_t); IntSetVal* isv_infty = IntSetVal::a(-IntVal::infinity(), IntVal::infinity()); infinity = new SetLit(Location(), isv_infty); ids.forall = ASTString("forall"); ids.forall_reif = ASTString("forall_reif"); ids.exists = ASTString("exists"); ids.clause = ASTString("clause"); ids.bool2int = ASTString("bool2int"); ids.int2float = ASTString("int2float"); ids.bool2float = ASTString("bool2float"); ids.assert = ASTString("assert"); ids.mzn_deprecate = ASTString("mzn_deprecate"); ids.trace = ASTString("trace"); ids.sum = ASTString("sum"); ids.lin_exp = ASTString("lin_exp"); ids.element = ASTString("element"); ids.show = ASTString("show"); ids.output = ASTString("output"); ids.fix = ASTString("fix"); ids.int_.lin_eq = ASTString("int_lin_eq"); ids.int_.lin_le = ASTString("int_lin_le"); ids.int_.lin_ne = ASTString("int_lin_ne"); ids.int_.plus = ASTString("int_plus"); ids.int_.minus = ASTString("int_minus"); ids.int_.times = ASTString("int_times"); ids.int_.div = ASTString("int_div"); ids.int_.mod = ASTString("int_mod"); ids.int_.lt = ASTString("int_lt"); ids.int_.le = ASTString("int_le"); ids.int_.gt = ASTString("int_gt"); ids.int_.ge = ASTString("int_ge"); ids.int_.eq = ASTString("int_eq"); ids.int_.ne = ASTString("int_ne"); ids.int_reif.lin_eq = ASTString("int_lin_eq_reif"); ids.int_reif.lin_le = ASTString("int_lin_le_reif"); ids.int_reif.lin_ne = ASTString("int_lin_ne_reif"); ids.int_reif.plus = ASTString("int_plus_reif"); ids.int_reif.minus = ASTString("int_minus_reif"); ids.int_reif.times = ASTString("int_times_reif"); ids.int_reif.div = ASTString("int_div_reif"); ids.int_reif.mod = ASTString("int_mod_reif"); ids.int_reif.lt = ASTString("int_lt_reif"); ids.int_reif.le = ASTString("int_le_reif"); ids.int_reif.gt = ASTString("int_gt_reif"); ids.int_reif.ge = ASTString("int_ge_reif"); ids.int_reif.eq = ASTString("int_eq_reif"); ids.int_reif.ne = ASTString("int_ne_reif"); ids.float_.lin_eq = ASTString("float_lin_eq"); ids.float_.lin_le = ASTString("float_lin_le"); ids.float_.lin_lt = ASTString("float_lin_lt"); ids.float_.lin_ne = ASTString("float_lin_ne"); ids.float_.plus = ASTString("float_plus"); ids.float_.minus = ASTString("float_minus"); ids.float_.times = ASTString("float_times"); ids.float_.div = ASTString("float_div"); ids.float_.mod = ASTString("float_mod"); ids.float_.lt = ASTString("float_lt"); ids.float_.le = ASTString("float_le"); ids.float_.gt = ASTString("float_gt"); ids.float_.ge = ASTString("float_ge"); ids.float_.eq = ASTString("float_eq"); ids.float_.ne = ASTString("float_ne"); ids.float_.in = ASTString("float_in"); ids.float_.dom = ASTString("float_dom"); ids.float_reif.lin_eq = ASTString("float_lin_eq_reif"); ids.float_reif.lin_le = ASTString("float_lin_le_reif"); ids.float_reif.lin_lt = ASTString("float_lin_lt_reif"); ids.float_reif.lin_ne = ASTString("float_lin_ne_reif"); ids.float_reif.plus = ASTString("float_plus_reif"); ids.float_reif.minus = ASTString("float_minus_reif"); ids.float_reif.times = ASTString("float_times_reif"); ids.float_reif.div = ASTString("float_div_reif"); ids.float_reif.mod = ASTString("float_mod_reif"); ids.float_reif.lt = ASTString("float_lt_reif"); ids.float_reif.le = ASTString("float_le_reif"); ids.float_reif.gt = ASTString("float_gt_reif"); ids.float_reif.ge = ASTString("float_ge_reif"); ids.float_reif.eq = ASTString("float_eq_reif"); ids.float_reif.ne = ASTString("float_ne_reif"); ids.float_reif.in = ASTString("float_in_reif"); ids.bool_eq = ASTString("bool_eq"); ids.bool_eq_reif = ASTString("bool_eq_reif"); ids.bool_clause = ASTString("bool_clause"); ids.bool_clause_reif = ASTString("bool_clause_reif"); ids.bool_xor = ASTString("bool_xor"); ids.array_bool_or = ASTString("array_bool_or"); ids.array_bool_and = ASTString("array_bool_and"); ids.set_eq = ASTString("set_eq"); ids.set_in = ASTString("set_in"); ids.set_card = ASTString("set_card"); ids.pow = ASTString("pow"); ids.introduced_var = ASTString("__INTRODUCED"); ids.anonEnumFromStrings = ASTString("anon_enum"); ctx.root = new Id(Location(),ASTString("ctx_root"),NULL); ctx.root->type(Type::ann()); ctx.pos = new Id(Location(),ASTString("ctx_pos"),NULL); ctx.pos->type(Type::ann()); ctx.neg = new Id(Location(),ASTString("ctx_neg"),NULL); ctx.neg->type(Type::ann()); ctx.mix = new Id(Location(),ASTString("ctx_mix"),NULL); ctx.mix->type(Type::ann()); ann.output_var = new Id(Location(), ASTString("output_var"), NULL); ann.output_var->type(Type::ann()); ann.output_only = new Id(Location(), ASTString("output_only"), NULL); ann.output_only->type(Type::ann()); ann.output_array = ASTString("output_array"); ann.add_to_output = new Id(Location(), ASTString("add_to_output"), NULL); ann.add_to_output->type(Type::ann()); ann.mzn_check_var = new Id(Location(), ASTString("mzn_check_var"), NULL); ann.mzn_check_var->type(Type::ann()); ann.mzn_check_enum_var = ASTString("mzn_check_enum_var"); ann.is_defined_var = new Id(Location(), ASTString("is_defined_var"), NULL); ann.is_defined_var->type(Type::ann()); ann.defines_var = ASTString("defines_var"); ann.is_reverse_map = new Id(Location(), ASTString("is_reverse_map"), NULL); ann.is_reverse_map->type(Type::ann()); ann.promise_total = new Id(Location(), ASTString("promise_total"), NULL); ann.promise_total->type(Type::ann()); ann.maybe_partial = new Id(Location(), ASTString("maybe_partial"), NULL); ann.maybe_partial->type(Type::ann()); ann.doc_comment = ASTString("doc_comment"); ann.mzn_path = ASTString("mzn_path"); ann.is_introduced = ASTString("is_introduced"); ann.user_cut = new Id(Location(), ASTString("user_cut"), NULL); ann.user_cut->type(Type::ann()); ann.lazy_constraint = new Id(Location(), ASTString("lazy_constraint"), NULL); ann.lazy_constraint->type(Type::ann()); #ifndef NDEBUG ann.mzn_break_here = new Id(Location(), ASTString("mzn_break_here"), NULL); ann.mzn_break_here->type(Type::ann()); #endif ann.rhs_from_assignment = new Id(Location(), ASTString("mzn_rhs_from_assignment"), NULL); ann.rhs_from_assignment->type(Type::ann()); ann.domain_change_constraint = new Id(Location(), ASTString("domain_change_constraint"), NULL); ann.domain_change_constraint->type(Type::ann()); ann.mzn_deprecated = ASTString("mzn_deprecated"); var_redef = new FunctionI(Location(),"__internal_var_redef",new TypeInst(Location(),Type::varbool()), std::vector()); cli.cmdlineData_short_str = ASTString("-D"); cli.cmdlineData_str = ASTString("--cmdline-data"); cli.datafile_str = ASTString("--data"); cli.datafile_short_str = ASTString("-d"); cli.globalsDir_str = ASTString("--globals-dir"); cli.globalsDir_alt_str = ASTString("--mzn-globals-dir"); cli.globalsDir_short_str = ASTString("-G"); cli.help_str = ASTString("--help"); cli.help_short_str = ASTString("-h"); cli.ignoreStdlib_str = ASTString("--ignore-stdlib"); cli.include_str = ASTString("-I"); cli.inputFromStdin_str = ASTString("--input-from-stdin"); cli.instanceCheckOnly_str = ASTString("--instance-check-only"); cli.newfzn_str = ASTString("--newfzn"); cli.no_optimize_str = ASTString("--no-optimize"); cli.no_optimize_alt_str = ASTString("--no-optimise"); cli.no_outputOzn_str = ASTString("--no-output-ozn"); cli.no_outputOzn_short_str = ASTString("-O-"); cli.no_typecheck_str = ASTString("--no-typecheck"); cli.outputBase_str = ASTString("--output-base"); cli.outputFznToStdout_str = ASTString("--output-to-stdout"); cli.outputFznToStdout_alt_str = ASTString("--output-fzn-to-stdout"); cli.outputOznToFile_str = ASTString("--output-ozn-to-file"); cli.outputOznToStdout_str = ASTString("--output-ozn-to-stdout"); cli.outputFznToFile_alt_str = ASTString("--output-fzn-to-file"); cli.outputFznToFile_short_str = ASTString("-o"); cli.outputFznToFile_str = ASTString("--output-to-file"); cli.rangeDomainsOnly_str = ASTString("--only-range-domains"); cli.statistics_str = ASTString("--statistics"); cli.statistics_short_str = ASTString("-s"); cli.stdlib_str = ASTString("--stdlib-dir"); cli.verbose_str = ASTString("--verbose"); cli.verbose_short_str = ASTString("-v"); cli.version_str = ASTString("--version"); cli.werror_str = ASTString("-Werror"); cli.solver.all_sols_str = ASTString("-a"); cli.solver.fzn_solver_str = ASTString("--solver"); opts.cmdlineData = ASTString("cmdlineData"); opts.datafile = ASTString("datafile"); opts.datafiles = ASTString("datafiles"); opts.fznToFile = ASTString("fznToFile"); opts.fznToStdout = ASTString("fznToStdout"); opts.globalsDir = ASTString("globalsDir"); opts.ignoreStdlib = ASTString("ignoreStdlib"); opts.includeDir = ASTString("includeDir"); opts.includePaths = ASTString("includePaths"); opts.inputFromStdin = ASTString("inputStdin"); opts.instanceCheckOnly = ASTString("instanceCheckOnly"); opts.model = ASTString("model"); opts.newfzn = ASTString("newfzn"); opts.noOznOutput = ASTString("noOznOutput"); opts.optimize = ASTString("optimize"); opts.outputBase = ASTString("outputBase"); opts.oznToFile = ASTString("oznToFile"); opts.oznToStdout = ASTString("oznToStdout"); opts.rangeDomainsOnly = ASTString("rangeDomainsOnly"); opts.statistics = ASTString("statistics"); opts.stdlib = ASTString("stdlib"); opts.typecheck = ASTString("typecheck"); opts.verbose = ASTString("verbose"); opts.werror = ASTString("werror"); opts.solver.allSols = ASTString("allSols"); opts.solver.numSols = ASTString("numSols"); opts.solver.threads = ASTString("threads"); opts.solver.fzn_solver = ASTString("fznsolver"); opts.solver.fzn_flags = ASTString("fzn_flags"); opts.solver.fzn_flag = ASTString("fzn_flag"); opts.solver.fzn_time_limit_ms = ASTString("fzn_time_limit_ms"); opts.solver.fzn_sigint = ASTString("fzn_sigint"); cli_cat.general = ASTString("General Options"); cli_cat.io = ASTString("Input/Output Options"); cli_cat.solver = ASTString("Solver Options"); cli_cat.translation = ASTString("Translation Options"); std::vector v; v.push_back(ti); v.push_back(lit_true); v.push_back(var_true); v.push_back(lit_false); v.push_back(var_false); v.push_back(var_ignore); v.push_back(absent); v.push_back(infinity); v.push_back(new StringLit(Location(),ids.forall)); v.push_back(new StringLit(Location(),ids.exists)); v.push_back(new StringLit(Location(),ids.clause)); v.push_back(new StringLit(Location(),ids.bool2int)); v.push_back(new StringLit(Location(),ids.int2float)); v.push_back(new StringLit(Location(),ids.bool2float)); v.push_back(new StringLit(Location(),ids.sum)); v.push_back(new StringLit(Location(),ids.lin_exp)); v.push_back(new StringLit(Location(),ids.element)); v.push_back(new StringLit(Location(),ids.show)); v.push_back(new StringLit(Location(),ids.output)); v.push_back(new StringLit(Location(),ids.fix)); v.push_back(new StringLit(Location(),ids.int_.lin_eq)); v.push_back(new StringLit(Location(),ids.int_.lin_le)); v.push_back(new StringLit(Location(),ids.int_.lin_ne)); v.push_back(new StringLit(Location(),ids.int_.plus)); v.push_back(new StringLit(Location(),ids.int_.minus)); v.push_back(new StringLit(Location(),ids.int_.times)); v.push_back(new StringLit(Location(),ids.int_.div)); v.push_back(new StringLit(Location(),ids.int_.mod)); v.push_back(new StringLit(Location(),ids.int_.lt)); v.push_back(new StringLit(Location(),ids.int_.le)); v.push_back(new StringLit(Location(),ids.int_.gt)); v.push_back(new StringLit(Location(),ids.int_.ge)); v.push_back(new StringLit(Location(),ids.int_.eq)); v.push_back(new StringLit(Location(),ids.int_.ne)); v.push_back(new StringLit(Location(),ids.int_reif.lin_eq)); v.push_back(new StringLit(Location(),ids.int_reif.lin_le)); v.push_back(new StringLit(Location(),ids.int_reif.lin_ne)); v.push_back(new StringLit(Location(),ids.int_reif.plus)); v.push_back(new StringLit(Location(),ids.int_reif.minus)); v.push_back(new StringLit(Location(),ids.int_reif.times)); v.push_back(new StringLit(Location(),ids.int_reif.div)); v.push_back(new StringLit(Location(),ids.int_reif.mod)); v.push_back(new StringLit(Location(),ids.int_reif.lt)); v.push_back(new StringLit(Location(),ids.int_reif.le)); v.push_back(new StringLit(Location(),ids.int_reif.gt)); v.push_back(new StringLit(Location(),ids.int_reif.ge)); v.push_back(new StringLit(Location(),ids.int_reif.eq)); v.push_back(new StringLit(Location(),ids.int_reif.ne)); v.push_back(new StringLit(Location(),ids.float_.lin_eq)); v.push_back(new StringLit(Location(),ids.float_.lin_le)); v.push_back(new StringLit(Location(),ids.float_.lin_lt)); v.push_back(new StringLit(Location(),ids.float_.lin_ne)); v.push_back(new StringLit(Location(),ids.float_.plus)); v.push_back(new StringLit(Location(),ids.float_.minus)); v.push_back(new StringLit(Location(),ids.float_.times)); v.push_back(new StringLit(Location(),ids.float_.div)); v.push_back(new StringLit(Location(),ids.float_.mod)); v.push_back(new StringLit(Location(),ids.float_.lt)); v.push_back(new StringLit(Location(),ids.float_.le)); v.push_back(new StringLit(Location(),ids.float_.gt)); v.push_back(new StringLit(Location(),ids.float_.ge)); v.push_back(new StringLit(Location(),ids.float_.eq)); v.push_back(new StringLit(Location(),ids.float_.ne)); v.push_back(new StringLit(Location(),ids.float_.in)); v.push_back(new StringLit(Location(),ids.float_.dom)); v.push_back(new StringLit(Location(),ids.float_reif.lin_eq)); v.push_back(new StringLit(Location(),ids.float_reif.lin_le)); v.push_back(new StringLit(Location(),ids.float_reif.lin_lt)); v.push_back(new StringLit(Location(),ids.float_reif.lin_ne)); v.push_back(new StringLit(Location(),ids.float_reif.plus)); v.push_back(new StringLit(Location(),ids.float_reif.minus)); v.push_back(new StringLit(Location(),ids.float_reif.times)); v.push_back(new StringLit(Location(),ids.float_reif.div)); v.push_back(new StringLit(Location(),ids.float_reif.mod)); v.push_back(new StringLit(Location(),ids.float_reif.lt)); v.push_back(new StringLit(Location(),ids.float_reif.le)); v.push_back(new StringLit(Location(),ids.float_reif.gt)); v.push_back(new StringLit(Location(),ids.float_reif.ge)); v.push_back(new StringLit(Location(),ids.float_reif.eq)); v.push_back(new StringLit(Location(),ids.float_reif.ne)); v.push_back(new StringLit(Location(),ids.float_reif.in)); v.push_back(new StringLit(Location(),ids.bool_eq)); v.push_back(new StringLit(Location(),ids.bool_eq_reif)); v.push_back(new StringLit(Location(),ids.bool_clause)); v.push_back(new StringLit(Location(),ids.bool_clause_reif)); v.push_back(new StringLit(Location(),ids.bool_xor)); v.push_back(new StringLit(Location(),ids.array_bool_or)); v.push_back(new StringLit(Location(),ids.array_bool_and)); v.push_back(new StringLit(Location(),ids.set_eq)); v.push_back(new StringLit(Location(),ids.set_in)); v.push_back(new StringLit(Location(),ids.set_card)); v.push_back(new StringLit(Location(),ids.pow)); v.push_back(new StringLit(Location(),ids.assert)); v.push_back(new StringLit(Location(),ids.mzn_deprecate)); v.push_back(new StringLit(Location(),ids.trace)); v.push_back(new StringLit(Location(),ids.introduced_var)); v.push_back(new StringLit(Location(),ids.anonEnumFromStrings)); v.push_back(ctx.root); v.push_back(ctx.pos); v.push_back(ctx.neg); v.push_back(ctx.mix); v.push_back(ann.output_var); v.push_back(ann.output_only); v.push_back(ann.add_to_output); v.push_back(ann.mzn_check_var); v.push_back(new StringLit(Location(),ann.mzn_check_enum_var)); v.push_back(new StringLit(Location(),ann.output_array)); v.push_back(ann.is_defined_var); v.push_back(new StringLit(Location(),ann.defines_var)); v.push_back(ann.is_reverse_map); v.push_back(ann.promise_total); v.push_back(ann.maybe_partial); v.push_back(new StringLit(Location(),ann.doc_comment)); v.push_back(new StringLit(Location(),ann.mzn_path)); v.push_back(new StringLit(Location(), ann.is_introduced)); v.push_back(ann.user_cut); v.push_back(ann.lazy_constraint); #ifndef NDEBUG v.push_back(ann.mzn_break_here); #endif v.push_back(ann.rhs_from_assignment); v.push_back(ann.domain_change_constraint); v.push_back(new StringLit(Location(), ann.mzn_deprecated)); v.push_back(new StringLit(Location(),cli.cmdlineData_short_str)); v.push_back(new StringLit(Location(),cli.cmdlineData_str)); v.push_back(new StringLit(Location(),cli.datafile_short_str)); v.push_back(new StringLit(Location(),cli.datafile_str)); v.push_back(new StringLit(Location(),cli.globalsDir_alt_str)); v.push_back(new StringLit(Location(),cli.globalsDir_short_str)); v.push_back(new StringLit(Location(),cli.globalsDir_str)); v.push_back(new StringLit(Location(),cli.help_short_str)); v.push_back(new StringLit(Location(),cli.help_str)); v.push_back(new StringLit(Location(),cli.ignoreStdlib_str)); v.push_back(new StringLit(Location(),cli.include_str)); v.push_back(new StringLit(Location(),cli.inputFromStdin_str)); v.push_back(new StringLit(Location(),cli.instanceCheckOnly_str)); v.push_back(new StringLit(Location(),cli.newfzn_str)); v.push_back(new StringLit(Location(),cli.no_optimize_alt_str)); v.push_back(new StringLit(Location(),cli.no_optimize_str)); v.push_back(new StringLit(Location(),cli.no_outputOzn_short_str)); v.push_back(new StringLit(Location(),cli.no_outputOzn_str)); v.push_back(new StringLit(Location(),cli.no_typecheck_str)); v.push_back(new StringLit(Location(),cli.outputBase_str)); v.push_back(new StringLit(Location(),cli.outputFznToStdout_alt_str)); v.push_back(new StringLit(Location(),cli.outputFznToStdout_str)); v.push_back(new StringLit(Location(),cli.outputOznToFile_str)); v.push_back(new StringLit(Location(),cli.outputOznToStdout_str)); v.push_back(new StringLit(Location(),cli.outputFznToFile_alt_str)); v.push_back(new StringLit(Location(),cli.outputFznToFile_short_str)); v.push_back(new StringLit(Location(),cli.outputFznToFile_str)); v.push_back(new StringLit(Location(),cli.rangeDomainsOnly_str)); v.push_back(new StringLit(Location(),cli.statistics_short_str)); v.push_back(new StringLit(Location(),cli.statistics_str)); v.push_back(new StringLit(Location(),cli.stdlib_str)); v.push_back(new StringLit(Location(),cli.verbose_short_str)); v.push_back(new StringLit(Location(),cli.verbose_str)); v.push_back(new StringLit(Location(),cli.version_str)); v.push_back(new StringLit(Location(),cli.werror_str)); v.push_back(new StringLit(Location(),cli.solver.all_sols_str)); v.push_back(new StringLit(Location(),cli.solver.fzn_solver_str)); v.push_back(new StringLit(Location(),opts.cmdlineData)); v.push_back(new StringLit(Location(),opts.datafile)); v.push_back(new StringLit(Location(),opts.datafiles)); v.push_back(new StringLit(Location(),opts.fznToFile)); v.push_back(new StringLit(Location(),opts.fznToStdout)); v.push_back(new StringLit(Location(),opts.globalsDir)); v.push_back(new StringLit(Location(),opts.ignoreStdlib)); v.push_back(new StringLit(Location(),opts.includePaths)); v.push_back(new StringLit(Location(),opts.includeDir)); v.push_back(new StringLit(Location(),opts.inputFromStdin)); v.push_back(new StringLit(Location(),opts.instanceCheckOnly)); v.push_back(new StringLit(Location(),opts.model)); v.push_back(new StringLit(Location(),opts.newfzn)); v.push_back(new StringLit(Location(),opts.noOznOutput)); v.push_back(new StringLit(Location(),opts.optimize)); v.push_back(new StringLit(Location(),opts.outputBase)); v.push_back(new StringLit(Location(),opts.oznToFile)); v.push_back(new StringLit(Location(),opts.oznToStdout)); v.push_back(new StringLit(Location(),opts.rangeDomainsOnly)); v.push_back(new StringLit(Location(),opts.statistics)); v.push_back(new StringLit(Location(),opts.stdlib)); v.push_back(new StringLit(Location(),opts.typecheck)); v.push_back(new StringLit(Location(),opts.verbose)); v.push_back(new StringLit(Location(),opts.werror)); v.push_back(new StringLit(Location(),opts.solver.allSols)); v.push_back(new StringLit(Location(),opts.solver.numSols)); v.push_back(new StringLit(Location(),opts.solver.threads)); v.push_back(new StringLit(Location(),opts.solver.fzn_solver)); v.push_back(new StringLit(Location(),opts.solver.fzn_flags)); v.push_back(new StringLit(Location(),opts.solver.fzn_flag)); v.push_back(new StringLit(Location(),opts.solver.fzn_time_limit_ms)); v.push_back(new StringLit(Location(),opts.solver.fzn_sigint)); v.push_back(new StringLit(Location(),cli_cat.general)); v.push_back(new StringLit(Location(),cli_cat.io)); v.push_back(new StringLit(Location(),cli_cat.solver)); v.push_back(new StringLit(Location(),cli_cat.translation)); m = new Model(); m->addItem(new ConstraintI(Location(),new ArrayLit(Location(),v))); m->addItem(var_redef); } const int Constants::max_array_size; Constants& constants(void) { static Constants _c; return _c; } Annotation::~Annotation(void) { delete _s; } bool Annotation::contains(Expression* e) const { return _s && _s->contains(e); } bool Annotation::isEmpty(void) const { return _s == NULL || _s->isEmpty(); } ExpressionSetIter Annotation::begin(void) const { return _s == NULL ? ExpressionSetIter(true) : _s->begin(); } ExpressionSetIter Annotation::end(void) const { return _s == NULL ? ExpressionSetIter(true) : _s->end(); } void Annotation::add(Expression* e) { if (_s == NULL) _s = new ExpressionSet; if (e) _s->insert(e); } void Annotation::add(std::vector e) { if (_s == NULL) _s = new ExpressionSet; for (unsigned int i=static_cast(e.size()); i--;) if (e[i]) _s->insert(e[i]); } void Annotation::remove(Expression* e) { if (_s && e) { _s->remove(e); } } void Annotation::removeCall(const ASTString& id) { if (_s==NULL) return; std::vector toRemove; for (ExpressionSetIter it=_s->begin(); it != _s->end(); ++it) { if (Call* c = (*it)->dyn_cast()) { if (c->id() == id) toRemove.push_back(*it); } } for (unsigned int i=static_cast(toRemove.size()); i--;) _s->remove(toRemove[i]); } Call* Annotation::getCall(const ASTString& id) const { if (_s==NULL) return NULL; for (ExpressionSetIter it=_s->begin(); it != _s->end(); ++it) { if (Call* c = (*it)->dyn_cast()) { if (c->id() == id) return c; } } return NULL; } bool Annotation::containsCall(const MiniZinc::ASTString& id) const { if (_s==NULL) return false; for (ExpressionSetIter it=_s->begin(); it != _s->end(); ++it) { if (Call* c = (*it)->dyn_cast()) { if (c->id() == id) return true; } } return false; } void Annotation::clear(void) { if (_s) { _s->clear(); } } void Annotation::merge(const Annotation& ann) { if (ann._s == NULL) return; if (_s == NULL) { _s = new ExpressionSet; } for (ExpressionSetIter it=ann.begin(); it != ann.end(); ++it) { _s->insert(*it); } } Expression* getAnnotation(const Annotation& ann, std::string str) { for(ExpressionSetIter i = ann.begin(); i != ann.end(); ++i) { Expression* e = *i; if((e->isa() && e->cast()->str().str() == str) || (e->isa() && e->cast()->id().str() == str)) return e; } return NULL; } Expression* getAnnotation(const Annotation& ann, const ASTString& str) { for(ExpressionSetIter i = ann.begin(); i != ann.end(); ++i) { Expression* e = *i; if((e->isa() && e->cast()->str() == str) || (e->isa() && e->cast()->id() == str)) return e; } return NULL; } } libminizinc-2.4.2/lib/astexception.cpp000066400000000000000000000015441360574160400200200ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include namespace MiniZinc { LocationException::LocationException(EnvI& env, const Location& loc, const std::string& msg) : Exception(msg), _loc(loc) { env.createErrorStack(); } ResultUndefinedError::ResultUndefinedError(EnvI& env, const Location& loc, const std::string& msg) : LocationException(env,loc,msg) { if (env.in_maybe_partial==0) env.addWarning("undefined result becomes false in Boolean context\n ("+msg+")"); } } libminizinc-2.4.2/lib/aststring.cpp000066400000000000000000000020121360574160400173170ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #ifndef HAS_MEMCPY_S namespace { void memcpy_s(char* dest, size_t, const char* src, size_t count) { memcpy(dest,src,count); } } #endif namespace MiniZinc { ASTStringO::ASTStringO(const std::string& s) : ASTChunk(s.size()+sizeof(size_t)+1) { memcpy_s(_data+sizeof(size_t),s.size()+1,s.c_str(),s.size()); *(_data+sizeof(size_t)+s.size())=0; std::hash h; reinterpret_cast(_data)[0] = h(s); } ASTStringO* ASTStringO::a(const std::string& s) { ASTStringO* as = static_cast(alloc(1+sizeof(size_t)+s.size())); new (as) ASTStringO(s); return as; } } libminizinc-2.4.2/lib/astvec.cpp000066400000000000000000000014001360574160400165660ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include namespace MiniZinc { ASTIntVecO::ASTIntVecO(const std::vector& v) : ASTChunk(sizeof(int)*v.size()) { for (unsigned int i=static_cast(v.size()); i--;) (*this)[i] = v[i]; } ASTIntVecO* ASTIntVecO::a(const std::vector& v) { ASTIntVecO* ao = static_cast(alloc(sizeof(int)*v.size())); new (ao) ASTIntVecO(v); return ao; } }libminizinc-2.4.2/lib/builtins.cpp000066400000000000000000003165741360574160400171570ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace MiniZinc { void rb(EnvI& env, Model* m, const ASTString& id, const std::vector& t, FunctionI::builtin_e b, bool fromGlobals=false) { FunctionI* fi = m->matchFn(env,id,t,false); if (fi) { fi->_builtins.e = b; } else if (!fromGlobals) { throw InternalError("no definition found for builtin "+id.str()); } } void rb(EnvI& env, Model* m, const ASTString& id, const std::vector& t, FunctionI::builtin_f b, bool fromGlobals=false) { FunctionI* fi = m->matchFn(env,id,t,false); if (fi) { fi->_builtins.f = b; } else if (!fromGlobals) { throw InternalError("no definition found for builtin "+id.str()); } } void rb(EnvI& env, Model* m, const ASTString& id, const std::vector& t, FunctionI::builtin_i b, bool fromGlobals=false) { FunctionI* fi = m->matchFn(env,id,t,false); if (fi) { fi->_builtins.i = b; } else if (!fromGlobals) { throw InternalError("no definition found for builtin "+id.str()); } } void rb(EnvI& env, Model* m, const ASTString& id, const std::vector& t, FunctionI::builtin_b b, bool fromGlobals=false) { FunctionI* fi = m->matchFn(env,id,t,false); if (fi) { fi->_builtins.b = b; } else if (!fromGlobals) { throw InternalError("no definition found for builtin "+id.str()); } } void rb(EnvI& env, Model* m, const ASTString& id, const std::vector& t, FunctionI::builtin_s b, bool fromGlobals=false) { FunctionI* fi = m->matchFn(env,id,t,false); if (fi) { fi->_builtins.s = b; } else if (!fromGlobals) { throw InternalError("no definition found for builtin "+id.str()); } } void rb(EnvI& env, Model* m, const ASTString& id, const std::vector& t, FunctionI::builtin_str b, bool fromGlobals=false) { FunctionI* fi = m->matchFn(env,id,t,false); if (fi) { fi->_builtins.str = b; } else if (!fromGlobals) { throw InternalError("no definition found for builtin "+id.str()); } } IntVal b_int_min(EnvI& env, Call* call) { switch (call->n_args()) { case 1: if (call->arg(0)->type().is_set()) { throw EvalError(env, call->arg(0)->loc(), "sets not supported"); } else { GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); if (al->size()==0) throw ResultUndefinedError(env, al->loc(), "minimum of empty array is undefined"); IntVal m = eval_int(env,(*al)[0]); for (unsigned int i=1; isize(); i++) m = std::min(m, eval_int(env,(*al)[i])); return m; } case 2: { return std::min(eval_int(env,call->arg(0)),eval_int(env,call->arg(1))); } default: throw EvalError(env, Location(), "dynamic type error"); } } IntVal b_int_max(EnvI& env, Call* call) { switch (call->n_args()) { case 1: if (call->arg(0)->type().is_set()) { throw EvalError(env, call->arg(0)->loc(), "sets not supported"); } else { GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); if (al->size()==0) throw ResultUndefinedError(env, al->loc(), "maximum of empty array is undefined"); IntVal m = eval_int(env,(*al)[0]); for (unsigned int i=1; isize(); i++) m = std::max(m, eval_int(env,(*al)[i])); return m; } case 2: { return std::max(eval_int(env,call->arg(0)),eval_int(env,call->arg(1))); } default: throw EvalError(env, Location(), "dynamic type error"); } } IntVal b_arg_min_int(EnvI& env, Call* call) { GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); if (al->size()==0) throw ResultUndefinedError(env, al->loc(), "argmin of empty array is undefined"); IntVal m = eval_int(env,(*al)[0]); int m_idx = 0; for (unsigned int i=1; isize(); i++) { IntVal mi = eval_int(env,(*al)[i]); if (mi < m) { m = mi; m_idx = i; } } return m_idx+1; } IntVal b_arg_max_int(EnvI& env, Call* call) { GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); if (al->size()==0) throw ResultUndefinedError(env, al->loc(), "argmax of empty array is undefined"); IntVal m = eval_int(env,(*al)[0]); int m_idx = 0; for (unsigned int i=1; isize(); i++) { IntVal mi = eval_int(env,(*al)[i]); if (mi > m) { m = mi; m_idx = i; } } return m_idx+1; } IntVal b_arg_min_float(EnvI& env, Call* call) { GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); if (al->size()==0) throw ResultUndefinedError(env, al->loc(), "argmin of empty array is undefined"); FloatVal m = eval_float(env,(*al)[0]); int m_idx = 0; for (unsigned int i=1; isize(); i++) { FloatVal mi = eval_float(env,(*al)[i]); if (mi < m) { m = mi; m_idx = i; } } return m_idx+1; } IntVal b_arg_max_float(EnvI& env, Call* call) { GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); if (al->size()==0) throw ResultUndefinedError(env, al->loc(), "argmax of empty array is undefined"); FloatVal m = eval_float(env,(*al)[0]); int m_idx = 0; for (unsigned int i=1; isize(); i++) { FloatVal mi = eval_float(env,(*al)[i]); if (mi > m) { m = mi; m_idx = i; } } return m_idx+1; } IntVal b_abs_int(EnvI& env, Call* call) { assert(call->n_args()==1); return std::abs(eval_int(env,call->arg(0))); } FloatVal b_abs_float(EnvI& env, Call* call) { assert(call->n_args() ==1); return std::abs(eval_float(env,call->arg(0))); } bool b_has_bounds_int(EnvI& env, Call* call) { if (call->n_args() != 1) throw EvalError(env, Location(), "dynamic type error"); IntBounds ib = compute_int_bounds(env,call->arg(0)); return ib.valid && ib.l.isFinite() && ib.u.isFinite(); } bool b_has_bounds_float(EnvI& env, Call* call) { if (call->n_args() != 1) throw EvalError(env, Location(), "dynamic type error"); FloatBounds fb = compute_float_bounds(env,call->arg(0)); return fb.valid; } IntVal lb_varoptint(EnvI& env, Expression* e) { IntBounds b = compute_int_bounds(env,e); if (b.valid) return b.l; else return -IntVal::infinity(); } IntVal b_lb_varoptint(EnvI& env, Call* call) { if (call->n_args() != 1) throw EvalError(env, Location(), "dynamic type error"); return lb_varoptint(env,call->arg(0)); } bool b_occurs(EnvI& env, Call* call) { GCLock lock; return eval_par(env,call->arg(0)) != constants().absent; } IntVal b_deopt_int(EnvI& env, Call* call) { GCLock lock; Expression* e = eval_par(env,call->arg(0)); if (e==constants().absent) throw EvalError(env, e->loc(), "cannot evaluate deopt on absent value"); return eval_int(env,e); } bool b_deopt_bool(EnvI& env, Call* call) { GCLock lock; Expression* e = eval_par(env,call->arg(0)); if (e==constants().absent) throw EvalError(env, e->loc(), "cannot evaluate deopt on absent value"); return eval_bool(env,e); } FloatVal b_deopt_float(EnvI& env, Call* call) { GCLock lock; Expression* e = eval_par(env,call->arg(0)); if (e==constants().absent) throw EvalError(env, e->loc(), "cannot evaluate deopt on absent value"); return eval_float(env,e); } IntSetVal* b_deopt_intset(EnvI& env, Call* call) { GCLock lock; Expression* e = eval_par(env,call->arg(0)); if (e==constants().absent) throw EvalError(env, e->loc(), "cannot evaluate deopt on absent value"); return eval_intset(env,e); } std::string b_deopt_string(EnvI& env, Call* call) { GCLock lock; Expression* e = eval_par(env,call->arg(0)); if (e==constants().absent) throw EvalError(env, e->loc(), "cannot evaluate deopt on absent value"); return eval_string(env,e); } Expression* b_deopt_expr(EnvI& env, Call* call) { GCLock lock; Expression* e = eval_par(env,call->arg(0)); if (e==constants().absent) throw EvalError(env, e->loc(), "cannot evaluate deopt on absent value"); return e; }; IntVal b_array_lb_int(EnvI& env, Call* call) { assert(call->n_args()==1); Expression* e = follow_id_to_decl(call->arg(0)); bool foundMin = false; IntVal array_lb = -IntVal::infinity(); if (VarDecl* vd = e->dyn_cast()) { if (vd->ti()->domain()) { GCLock lock; IntSetVal* isv = eval_intset(env,vd->ti()->domain()); if (isv->size()!=0) { array_lb = isv->min(); foundMin = true; } } e = vd->e(); } if (e != NULL) { GCLock lock; ArrayLit* al = eval_array_lit(env,e); if (al->size()==0) throw EvalError(env, Location(), "lower bound of empty array undefined"); IntVal min = IntVal::infinity(); for (unsigned int i=0; isize(); i++) { IntBounds ib = compute_int_bounds(env,(*al)[i]); if (!ib.valid) goto b_array_lb_int_done; min = std::min(min, ib.l); } if (foundMin) array_lb = std::max(array_lb, min); else array_lb = min; foundMin = true; } b_array_lb_int_done: if (foundMin) { return array_lb; } else { return -IntVal::infinity(); } } IntVal ub_varoptint(EnvI& env, Expression* e) { IntBounds b = compute_int_bounds(env,e); if (b.valid) return b.u; else return IntVal::infinity(); } IntVal b_ub_varoptint(EnvI& env, Call* call) { if (call->n_args() != 1) throw EvalError(env, Location(), "dynamic type error"); return ub_varoptint(env,call->arg(0)); } IntVal b_array_ub_int(EnvI& env, Call* call) { assert(call->n_args()==1); Expression* e = follow_id_to_decl(call->arg(0)); bool foundMax = false; IntVal array_ub = IntVal::infinity(); if (VarDecl* vd = e->dyn_cast()) { if (vd->ti()->domain()) { GCLock lock; IntSetVal* isv = eval_intset(env,vd->ti()->domain()); if (isv->size()!=0) { array_ub = isv->max(); foundMax = true; } } e = vd->e(); } if (e != NULL) { GCLock lock; ArrayLit* al = eval_array_lit(env,e); if (al->size()==0) throw EvalError(env, Location(), "upper bound of empty array undefined"); IntVal max = -IntVal::infinity(); for (unsigned int i=0; isize(); i++) { IntBounds ib = compute_int_bounds(env,(*al)[i]); if (!ib.valid) goto b_array_ub_int_done; max = std::max(max, ib.u); } if (foundMax) array_ub = std::min(array_ub, max); else array_ub = max; foundMax = true; } b_array_ub_int_done: if (foundMax) { return array_ub; } else { return IntVal::infinity(); } } IntVal b_sum_int(EnvI& env, Call* call) { assert(call->n_args()==1); GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); if (al->size()==0) return 0; IntVal m = 0; for (unsigned int i=0; isize(); i++) m += eval_int(env,(*al)[i]); return m; } IntVal b_product_int(EnvI& env, Call* call) { assert(call->n_args()==1); GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); if (al->size()==0) return 1; IntVal m = 1; for (unsigned int i=0; isize(); i++) m *= eval_int(env,(*al)[i]); return m; } FloatVal b_product_float(EnvI& env, Call* call) { assert(call->n_args()==1); GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); if (al->size()==0) return 1; FloatVal m = 1.0; for (unsigned int i=0; isize(); i++) m *= eval_float(env,(*al)[i]); return m; } FloatVal lb_varoptfloat(EnvI& env, Expression* e) { FloatBounds b = compute_float_bounds(env,e); if (b.valid) return b.l; else throw EvalError(env, e->loc(),"cannot determine bounds"); } FloatVal ub_varoptfloat(EnvI& env, Expression* e) { FloatBounds b = compute_float_bounds(env,e); if (b.valid) return b.u; else throw EvalError(env, e->loc(),"cannot determine bounds"); } FloatVal b_lb_varoptfloat(EnvI& env, Call* call) { if (call->n_args() != 1) throw EvalError(env, Location(), "dynamic type error"); return lb_varoptfloat(env,call->arg(0)); } FloatVal b_ub_varoptfloat(EnvI& env, Call* call) { if (call->n_args() != 1) throw EvalError(env, Location(), "dynamic type error"); return ub_varoptfloat(env,call->arg(0)); } FloatVal b_array_lb_float(EnvI& env, Call* call) { assert(call->n_args()==1); Expression* e = follow_id_to_decl(call->arg(0)); bool foundMin = false; FloatVal array_lb = 0.0; if (VarDecl* vd = e->dyn_cast()) { if (vd->ti()->domain()) { FloatSetVal* fsv = eval_floatset(env, vd->ti()->domain()); array_lb = fsv->min(); foundMin = true; } e = vd->e(); } if (e != NULL) { GCLock lock; ArrayLit* al = eval_array_lit(env,e); if (al->size()==0) throw EvalError(env, Location(), "lower bound of empty array undefined"); bool min_valid = false; FloatVal min = 0.0; for (unsigned int i=0; isize(); i++) { FloatBounds fb = compute_float_bounds(env,(*al)[i]); if (!fb.valid) goto b_array_lb_float_done; if (min_valid) { min = std::min(min, fb.l); } else { min_valid = true; min = fb.l; } } assert(min_valid); if (foundMin) array_lb = std::max(array_lb, min); else array_lb = min; foundMin = true; } b_array_lb_float_done: if (foundMin) { return array_lb; } else { throw EvalError(env, e->loc(),"cannot determine lower bound"); } } FloatVal b_array_ub_float(EnvI& env, Call* call) { assert(call->n_args()==1); Expression* e = follow_id_to_decl(call->arg(0)); bool foundMax = false; FloatVal array_ub = 0.0; if (VarDecl* vd = e->dyn_cast()) { if (vd->ti()->domain()) { FloatSetVal* fsv = eval_floatset(env, vd->ti()->domain()); array_ub = fsv->max(); foundMax = true; } e = vd->e(); } if (e != NULL) { GCLock lock; ArrayLit* al = eval_array_lit(env,e); if (al->size()==0) throw EvalError(env, Location(), "upper bound of empty array undefined"); bool max_valid = false; FloatVal max = 0.0; for (unsigned int i=0; isize(); i++) { FloatBounds fb = compute_float_bounds(env,(*al)[i]); if (!fb.valid) goto b_array_ub_float_done; if (max_valid) { max = std::max(max, fb.u); } else { max_valid = true; max = fb.u; } } assert(max_valid); if (foundMax) array_ub = std::min(array_ub, max); else array_ub = max; foundMax = true; } b_array_ub_float_done: if (foundMax) { return array_ub; } else { throw EvalError(env, e->loc(),"cannot determine upper bound"); } } FloatVal b_sum_float(EnvI& env, Call* call) { assert(call->n_args()==1); GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); if (al->size()==0) return 0; FloatVal m = 0; for (unsigned int i=0; isize(); i++) m += eval_float(env,(*al)[i]); return m; } FloatVal b_float_min(EnvI& env, Call* call) { switch (call->n_args()) { case 1: if (call->arg(0)->type().is_set()) { throw EvalError(env, call->arg(0)->loc(), "sets not supported"); } else { GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); if (al->size()==0) throw EvalError(env, al->loc(), "min on empty array undefined"); FloatVal m = eval_float(env,(*al)[0]); for (unsigned int i=1; isize(); i++) m = std::min(m, eval_float(env,(*al)[i])); return m; } case 2: { return std::min(eval_float(env,call->arg(0)),eval_float(env,call->arg(1))); } default: throw EvalError(env, Location(), "dynamic type error"); } } FloatVal b_float_max(EnvI& env, Call* call) { switch (call->n_args()) { case 1: if (call->arg(0)->type().is_set()) { throw EvalError(env, call->arg(0)->loc(), "sets not supported"); } else { GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); if (al->size()==0) throw EvalError(env, al->loc(), "max on empty array undefined"); FloatVal m = eval_float(env,(*al)[0]); for (unsigned int i=1; isize(); i++) m = std::max(m, eval_float(env,(*al)[i])); return m; } case 2: { return std::max(eval_float(env,call->arg(0)),eval_float(env,call->arg(1))); } default: throw EvalError(env, Location(), "dynamic type error"); } } IntSetVal* b_index_set(EnvI& env, Expression* e, int i) { if (e->eid() != Expression::E_ID) { GCLock lock; ArrayLit* al = eval_array_lit(env,e); if (al->dims() < i) throw EvalError(env, e->loc(), "index_set: wrong dimension"); return IntSetVal::a(al->min(i-1),al->max(i-1)); } Id* id = e->cast(); if (id->decl() == NULL) throw EvalError(env, id->loc(), "undefined identifier"); if ( ( id->decl()->ti()->ranges().size()==1 && id->decl()->ti()->ranges()[0]->domain() != NULL && id->decl()->ti()->ranges()[0]->domain()->isa() ) || ( static_cast(id->decl()->ti()->ranges().size()) >= i && ( id->decl()->ti()->ranges()[i-1]->domain() == NULL || id->decl()->ti()->ranges()[i-1]->domain()->isa()) )) { GCLock lock; ArrayLit* al = eval_array_lit(env,id); if (al->dims() < i) throw EvalError(env, id->loc(), "index_set: wrong dimension"); return IntSetVal::a(al->min(i-1),al->max(i-1)); } if (static_cast(id->decl()->ti()->ranges().size()) < i) throw EvalError(env, id->loc(), "index_set: wrong dimension"); return eval_intset(env,id->decl()->ti()->ranges()[i-1]->domain()); } bool b_index_sets_agree(EnvI& env, Call* call) { if (call->n_args() != 2) throw EvalError(env, Location(), "index_sets_agree needs exactly two arguments"); GCLock lock; ArrayLit* al0 = eval_array_lit(env,call->arg(0)); ArrayLit* al1 = eval_array_lit(env,call->arg(1)); if (al0->type().dim() != al1->type().dim()) return false; for (int i=1; i<=al0->type().dim(); i++) { IntSetVal* index0 = b_index_set(env, al0, i); IntSetVal* index1 = b_index_set(env, al1, i); if (!index0->equal(index1)) return false; } return true; } IntSetVal* b_index_set1(EnvI& env, Call* call) { if (call->n_args() != 1) throw EvalError(env, Location(), "index_set needs exactly one argument"); return b_index_set(env,call->arg(0),1); } IntSetVal* b_index_set2(EnvI& env, Call* call) { if (call->n_args() != 1) throw EvalError(env, Location(), "index_set needs exactly one argument"); return b_index_set(env,call->arg(0),2); } IntSetVal* b_index_set3(EnvI& env, Call* call) { if (call->n_args() != 1) throw EvalError(env, Location(), "index_set needs exactly one argument"); return b_index_set(env,call->arg(0),3); } IntSetVal* b_index_set4(EnvI& env, Call* call) { if (call->n_args() != 1) throw EvalError(env, Location(), "index_set needs exactly one argument"); return b_index_set(env,call->arg(0),4); } IntSetVal* b_index_set5(EnvI& env, Call* call) { if (call->n_args() != 1) throw EvalError(env, Location(), "index_set needs exactly one argument"); return b_index_set(env,call->arg(0),5); } IntSetVal* b_index_set6(EnvI& env, Call* call) { if (call->n_args() != 1) throw EvalError(env, Location(), "index_set needs exactly one argument"); return b_index_set(env,call->arg(0),6); } IntVal b_min_parsetint(EnvI& env, Call* call) { assert(call->n_args() == 1); IntSetVal* isv = eval_intset(env,call->arg(0)); return isv->min(); } IntVal b_max_parsetint(EnvI& env, Call* call) { assert(call->n_args() == 1); IntSetVal* isv = eval_intset(env,call->arg(0)); return isv->max(); } IntSetVal* b_lb_set(EnvI& env, Call* e) { Expression* ee = eval_par(env, e->arg(0)); if (ee->type().ispar()) { return eval_intset(env, ee); } return IntSetVal::a(); } IntSetVal* b_ub_set(EnvI& env, Expression* e) { IntSetVal* isv = compute_intset_bounds(env,e); if (isv) return isv; throw EvalError(env, e->loc(), "cannot determine bounds of set expression"); } IntSetVal* b_ub_set(EnvI& env, Call* call) { assert(call->n_args() == 1); return b_ub_set(env,call->arg(0)); } bool b_has_ub_set(EnvI& env, Call* call) { Expression* e = call->arg(0); for (;;) { switch (e->eid()) { case Expression::E_SETLIT: return true; case Expression::E_ID: { Id* id = e->cast(); if (id->decl()==NULL) throw EvalError(env, id->loc(),"undefined identifier"); if (id->decl()->e()==NULL) return id->decl()->ti()->domain() != NULL; else e = id->decl()->e(); } break; default: throw EvalError(env, e->loc(),"invalid argument to has_ub_set"); } } } IntSetVal* b_array_ub_set(EnvI& env, Call* call) { assert(call->n_args()==1); GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); if (al->size()==0) throw EvalError(env, Location(), "upper bound of empty array undefined"); IntSetVal* ub = b_ub_set(env,(*al)[0]); for (unsigned int i=1; isize(); i++) { IntSetRanges isr(ub); IntSetRanges r(b_ub_set(env,(*al)[i])); Ranges::Union u(isr,r); ub = IntSetVal::ai(u); } return ub; } IntSetVal* b_dom_varint(EnvI& env, Expression* e) { Id* lastid = NULL; Expression* cur = e; for (;;) { if (cur==NULL) { if (lastid==NULL || lastid->decl()->ti()->domain()==NULL) { IntBounds b = compute_int_bounds(env,e); if (b.valid) return IntSetVal::a(b.l,b.u); else return IntSetVal::a(-IntVal::infinity(),IntVal::infinity()); } else { return eval_intset(env,lastid->decl()->ti()->domain()); } } switch (cur->eid()) { case Expression::E_INTLIT: { IntVal v = cur->cast()->v(); return IntSetVal::a(v,v); } case Expression::E_ID: { lastid = cur->cast(); if (lastid->decl()==NULL) throw EvalError(env, lastid->loc(),"undefined identifier"); cur = lastid->decl()->e(); } break; case Expression::E_ARRAYACCESS: { bool success; cur = eval_arrayaccess(env,cur->cast(), success); if (!success) { cur = NULL; } } break; default: cur = NULL; break; } } } IntSetVal* b_dom_varint(EnvI& env, Call* call) { assert(call->n_args() == 1); return b_dom_varint(env,call->arg(0)); } IntSetVal* b_dom_bounds_array(EnvI& env, Call* call) { assert(call->n_args()==1); Expression* arg_e = call->arg(0); Expression* e = follow_id_to_decl(arg_e); bool foundBounds = false; IntVal array_lb = -IntVal::infinity(); IntVal array_ub = IntVal::infinity(); if (VarDecl* vd = e->dyn_cast()) { if (vd->ti()->domain()) { GCLock lock; IntSetVal* isv = eval_intset(env,vd->ti()->domain()); if (isv->size()!=0) { array_lb = isv->min(); array_ub = isv->max(); foundBounds = true; } } e = vd->e(); if (e==NULL) e = vd->flat()->e(); } if (foundBounds) { return IntSetVal::a(array_lb,array_ub); } if (e != NULL) { GCLock lock; ArrayLit* al = eval_array_lit(env,e); if (al->size()==0) throw EvalError(env, Location(), "lower bound of empty array undefined"); IntVal min = IntVal::infinity(); IntVal max = -IntVal::infinity(); for (unsigned int i=0; isize(); i++) { IntBounds ib = compute_int_bounds(env,(*al)[i]); if (!ib.valid) goto b_array_lb_int_done; min = std::min(min, ib.l); max = std::max(max, ib.u); } array_lb = std::max(array_lb, min); array_ub = std::min(array_ub, max); foundBounds = true; } b_array_lb_int_done: if (foundBounds) { return IntSetVal::a(array_lb,array_ub); } else { throw EvalError(env, e->loc(),"cannot determine lower bound"); } } IntSetVal* b_dom_array(EnvI& env, Call* call) { assert(call->n_args() == 1); Expression* ae = call->arg(0); ArrayLit* al = NULL; while (al==NULL) { switch (ae->eid()) { case Expression::E_ARRAYLIT: al = ae->cast(); break; case Expression::E_ID: { Id* id = ae->cast(); if (id->decl()==NULL) throw EvalError(env, id->loc(),"undefined identifier"); if (id->decl()->e()==NULL) { if (id->decl()->flat()==NULL) { throw EvalError(env, id->loc(),"array without initialiser"); } else { if (id->decl()->flat()->e()==NULL) { throw EvalError(env, id->loc(),"array without initialiser"); } ae = id->decl()->flat()->e(); } } else { ae = id->decl()->e(); } } break; default: throw EvalError(env, ae->loc(),"invalid argument to dom"); } } if (al->size()==0) return IntSetVal::a(); IntSetVal* isv = b_dom_varint(env,(*al)[0]); for (unsigned int i=1; isize(); i++) { IntSetRanges isr(isv); IntSetRanges r(b_dom_varint(env,(*al)[i])); Ranges::Union u(isr,r); isv = IntSetVal::ai(u); } return isv; } IntSetVal* b_compute_div_bounds(EnvI& env, Call* call) { assert(call->n_args()==2); IntBounds bx = compute_int_bounds(env,call->arg(0)); if (!bx.valid) throw EvalError(env, call->arg(0)->loc(),"cannot determine bounds"); /// TODO: better bounds if only some input bounds are infinite if (!bx.l.isFinite() || !bx.u.isFinite()) return constants().infinity->isv(); IntBounds by = compute_int_bounds(env,call->arg(1)); if (!by.valid) throw EvalError(env, call->arg(1)->loc(),"cannot determine bounds"); if (!by.l.isFinite() || !by.u.isFinite()) return constants().infinity->isv(); Ranges::Const byr(by.l,by.u); Ranges::Const by0(0,0); Ranges::Diff, Ranges::Const > byr0(byr,by0); IntVal min=IntVal::maxint(); IntVal max=IntVal::minint(); if (byr0()) { min = std::min(min, bx.l / byr0.min()); min = std::min(min, bx.l / byr0.max()); min = std::min(min, bx.u / byr0.min()); min = std::min(min, bx.u / byr0.max()); max = std::max(max, bx.l / byr0.min()); max = std::max(max, bx.l / byr0.max()); max = std::max(max, bx.u / byr0.min()); max = std::max(max, bx.u / byr0.max()); ++byr0; if (byr0()) { min = std::min(min, bx.l / byr0.min()); min = std::min(min, bx.l / byr0.max()); min = std::min(min, bx.u / byr0.min()); min = std::min(min, bx.u / byr0.max()); max = std::max(max, bx.l / byr0.min()); max = std::max(max, bx.l / byr0.max()); max = std::max(max, bx.u / byr0.min()); max = std::max(max, bx.u / byr0.max()); } } return IntSetVal::a(min,max); } ArrayLit* b_arrayXd(EnvI& env, Call* call, int d) { GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(d)); std::vector > dims(d); unsigned int dim1d = 1; for (int i=0; iarg(i)); if (di->size()==0) { dims[i] = std::pair(1,0); dim1d = 0; } else if (di->size() != 1) { throw EvalError(env, call->arg(i)->loc(), "arrayXd only defined for ranges"); } else { dims[i] = std::pair(static_cast(di->min(0).toInt()), static_cast(di->max(0).toInt())); dim1d *= dims[i].second-dims[i].first+1; } } if (dim1d != al->size()) throw EvalError(env, al->loc(), "mismatch in array dimensions"); ArrayLit* ret = new ArrayLit(al->loc(), *al, dims); Type t = al->type(); t.dim(d); ret->type(t); ret->flat(al->flat()); return ret; } Expression* b_array1d_list(EnvI& env, Call* call) { GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); if (al->dims()==1 && al->min(0)==1) { return call->arg(0)->isa() ? call->arg(0) : al; } ArrayLit* ret = new ArrayLit(al->loc(), *al); Type t = al->type(); t.dim(1); ret->type(t); ret->flat(al->flat()); return ret; } Expression* b_array1d(EnvI& env, Call* call) { return b_arrayXd(env,call,1); } Expression* b_array2d(EnvI& env, Call* call) { return b_arrayXd(env,call,2); } Expression* b_array3d(EnvI& env, Call* call) { return b_arrayXd(env,call,3); } Expression* b_array4d(EnvI& env, Call* call) { return b_arrayXd(env,call,4); } Expression* b_array5d(EnvI& env, Call* call) { return b_arrayXd(env,call,5); } Expression* b_array6d(EnvI& env, Call* call) { return b_arrayXd(env,call,6); } Expression* b_arrayXd(EnvI& env, Call* call) { GCLock lock; ArrayLit* al0 = eval_array_lit(env,call->arg(0)); ArrayLit* al1 = eval_array_lit(env,call->arg(1)); if (al0->dims()==al1->dims()) { bool sameDims = true; for (unsigned int i=al0->dims(); i--;) { if (al0->min(i)!=al1->min(i) || al0->max(i)!=al1->max(i)) { sameDims = false; break; } } if (sameDims) return call->arg(1)->isa() ? call->arg(1) : al1; } std::vector > dims(al0->dims()); for (unsigned int i=al0->dims(); i--;) { dims[i] = std::make_pair(al0->min(i), al0->max(i)); } ArrayLit* ret = new ArrayLit(al1->loc(), *al1, dims); Type t = al1->type(); t.dim(static_cast(dims.size())); ret->type(t); ret->flat(al1->flat()); return ret; } IntVal b_length(EnvI& env, Call* call) { GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); return al->size(); } IntVal b_bool2int(EnvI& env, Call* call) { return eval_bool(env,call->arg(0)) ? 1 : 0; } bool b_forall_par(EnvI& env, Call* call) { if (call->n_args()!=1) throw EvalError(env, Location(), "forall needs exactly one argument"); GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); for (unsigned int i=al->size(); i--;) if (!eval_bool(env,(*al)[i])) return false; return true; } bool b_exists_par(EnvI& env, Call* call) { if (call->n_args()!=1) throw EvalError(env, Location(), "exists needs exactly one argument"); GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); for (unsigned int i=al->size(); i--;) if (eval_bool(env,(*al)[i])) return true; return false; } bool b_clause_par(EnvI& env, Call* call) { if (call->n_args()!=2) throw EvalError(env, Location(), "clause needs exactly two arguments"); GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); for (unsigned int i=al->size(); i--;) if (eval_bool(env,(*al)[i])) return true; al = eval_array_lit(env,call->arg(1)); for (unsigned int i=al->size(); i--;) if (!eval_bool(env,(*al)[i])) return true; return false; } bool b_xorall_par(EnvI& env, Call* call) { if (call->n_args()!=1) throw EvalError(env, Location(), "xorall needs exactly one argument"); GCLock lock; int count = 0; ArrayLit* al = eval_array_lit(env,call->arg(0)); for (unsigned int i=al->size(); i--;) count += eval_bool(env,(*al)[i]); return count % 2 == 1; } bool b_iffall_par(EnvI& env, Call* call) { if (call->n_args()!=1) throw EvalError(env, Location(), "xorall needs exactly one argument"); GCLock lock; int count = 0; ArrayLit* al = eval_array_lit(env,call->arg(0)); for (unsigned int i=al->size(); i--;) count += eval_bool(env,(*al)[i]); return count % 2 == 0; } IntVal b_card(EnvI& env, Call* call) { if (call->n_args()!=1) throw EvalError(env, Location(), "card needs exactly one argument"); IntSetVal* isv = eval_intset(env,call->arg(0)); IntSetRanges isr(isv); return Ranges::cardinality(isr); } Expression* exp_is_fixed(EnvI& env, Expression* e) { GCLock lock; Expression* cur = eval_par(env,e); for (;;) { if (cur==NULL) return NULL; if (cur->type().ispar()) return cur; switch (cur->eid()) { case Expression::E_ID: cur = cur->cast()->decl(); break; case Expression::E_VARDECL: if (cur->type().st() != Type::ST_SET) { Expression* dom = cur->cast()->ti()->domain(); if (dom && (dom->isa() || dom->isa() || dom->isa())) return dom; } cur = cur->cast()->e(); break; default: return NULL; } } } bool b_is_fixed(EnvI& env, Call* call) { assert(call->n_args()==1); return exp_is_fixed(env,call->arg(0)) != NULL; } bool b_is_fixed_array(EnvI& env, Call* call) { assert(call->n_args()==1); GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); if (al->size()==0) return true; for (unsigned int i=0; isize(); i++) { if (exp_is_fixed(env,(*al)[i])==NULL) return false; } return true; } Expression* b_fix(EnvI& env, Call* call) { assert(call->n_args()==1); Expression* ret = exp_is_fixed(env,call->arg(0)); if (ret==NULL) throw EvalError(env, call->arg(0)->loc(), "expression is not fixed"); return ret; } IntVal b_fix_int(EnvI& env, Call* call) { return eval_int(env,b_fix(env,call)); } bool b_fix_bool(EnvI& env, Call* call) { return eval_bool(env,b_fix(env,call)); } FloatVal b_fix_float(EnvI& env, Call* call) { return eval_float(env,b_fix(env,call)); } IntSetVal* b_fix_set(EnvI& env, Call* call) { return eval_intset(env,b_fix(env,call)); } Expression* b_fix_array(EnvI& env, Call* call) { assert(call->n_args()==1); GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); std::vector fixed(al->size()); for (unsigned int i=0; iloc(), "expression is not fixed"); } ArrayLit* ret = new ArrayLit(Location(), fixed); Type tt = al->type(); tt.ti(Type::TI_PAR); ret->type(tt); return ret; } FloatVal b_int2float(EnvI& env, Call* call) { return eval_int(env,call->arg(0)); } IntVal b_ceil(EnvI& env, Call* call) { return static_cast(std::ceil(eval_float(env,call->arg(0)))); } IntVal b_floor(EnvI& env, Call* call) { return static_cast(std::floor(eval_float(env,call->arg(0)))); } IntVal b_round(EnvI& env, Call* call) { /// Cast to int truncates, so cannot just add 0.5 and cast return static_cast(std::round(eval_float(env,call->arg(0)).toDouble())); } FloatVal b_log10(EnvI& env, Call* call) { return std::log10(eval_float(env,call->arg(0)).toDouble()); } FloatVal b_log2(EnvI& env, Call* call) { return std::log(eval_float(env,call->arg(0)).toDouble()) / std::log(2.0); } FloatVal b_ln(EnvI& env, Call* call) { return std::log(eval_float(env,call->arg(0)).toDouble()); } FloatVal b_log(EnvI& env, Call* call) { return std::log(eval_float(env,call->arg(1)).toDouble()) / std::log(eval_float(env,call->arg(0)).toDouble()); } FloatVal b_exp(EnvI& env, Call* call) { return std::exp(eval_float(env,call->arg(0)).toDouble()); } FloatVal b_pow(EnvI& env, Call* call) { return std::pow(eval_float(env,call->arg(0)).toDouble(),eval_float(env,call->arg(1)).toDouble()); } IntVal b_pow_int(EnvI& env, Call* call) { IntVal p = eval_int(env,call->arg(0)); IntVal r = 1; long long int e = eval_int(env,call->arg(1)).toInt(); if (e < 0) throw EvalError(env, call->arg(1)->loc(), "Cannot raise integer to a negative power"); for (long long int i=e; i--;) r = r*p; return r; } FloatVal b_sqrt(EnvI& env, Call* call) { return std::sqrt(eval_float(env,call->arg(0)).toDouble()); } bool b_assert_bool(EnvI& env, Call* call) { assert(call->n_args()==2); GCLock lock; if (eval_bool(env,call->arg(0))) return true; StringLit* err = eval_par(env,call->arg(1))->cast(); throw EvalError(env, call->arg(0)->loc(),"Assertion failed: "+err->v().str()); } Expression* b_assert(EnvI& env, Call* call) { assert(call->n_args()==3); GCLock lock; if (eval_bool(env,call->arg(0))) return call->arg(2); StringLit* err = eval_par(env,call->arg(1))->cast(); throw EvalError(env, call->arg(0)->loc(),"Assertion failed: "+err->v().str()); } Expression* b_mzn_deprecate(EnvI& env, Call* call) { assert(call->n_args()==4); GCLock lock; std::string fnName = eval_string(env, call->arg(0)); if (env.deprecationWarnings.find(fnName)==env.deprecationWarnings.end()) { env.deprecationWarnings.insert(fnName); env.dumpStack(env.errstream, false); env.errstream << " The function/predicate `"<< fnName; env.errstream << "' was deprecated in MiniZinc version " << eval_string(env, call->arg(1)); env.errstream << ".\n More information can be found at " << eval_string(env, call->arg(2)) << ".\n"; } return call->arg(3); } bool b_abort(EnvI& env, Call* call) { GCLock lock; StringLit* err = eval_par(env,call->arg(0))->cast(); throw EvalError(env, call->arg(0)->loc(),"Abort: "+err->v().str()); } Expression* b_trace(EnvI& env, Call* call) { GCLock lock; StringLit* msg = eval_par(env,call->arg(0))->cast(); env.errstream << msg->v(); return call->n_args()==1 ? constants().lit_true : call->arg(1); } Expression* b_trace_stdout(EnvI& env, Call* call) { GCLock lock; StringLit* msg = eval_par(env,call->arg(0))->cast(); env.outstream << msg->v(); return call->n_args()==1 ? constants().lit_true : call->arg(1); } bool b_in_redundant_constraint(EnvI& env, Call*) { return env.in_redundant_constraint > 0; } Expression* b_set2array(EnvI& env, Call* call) { assert(call->n_args()==1); GCLock lock; IntSetVal* isv = eval_intset(env,call->arg(0)); std::vector elems; IntSetRanges isr(isv); for (Ranges::ToValues isr_v(isr); isr_v(); ++isr_v) elems.push_back(IntLit::a(isr_v.val())); ArrayLit* al = new ArrayLit(call->arg(0)->loc(),elems); al->type(Type::parint(1)); return al; } IntVal b_string_length(EnvI& env, Call* call) { GCLock lock; std::string s = eval_string(env,call->arg(0)); return s.size(); } std::string show(EnvI& env, Expression* exp) { std::ostringstream oss; GCLock lock; Printer p(oss,0,false); Expression* e = eval_par(env,exp); if (e->type().isvar()) { p.print(e); } else { e = eval_par(env,e); if (ArrayLit* al = e->dyn_cast()) { oss << "["; for (unsigned int i=0; isize(); i++) { p.print((*al)[i]); if (isize()-1) oss << ", "; } oss << "]"; } else { p.print(e); } } return oss.str(); } std::string b_show(EnvI& env, Call* call) { return show(env,call->arg(0)); } std::string b_showDznId(EnvI& env, Call* call) { GCLock lock; std::string s = eval_string(env, call->arg(0)); size_t nonIdChar = s.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"); size_t nonIdBegin = s.find_first_of("0123456789_"); if (nonIdChar!=std::string::npos || nonIdBegin==0) { s = "'"+s+"'"; } return s; } std::string b_show_json_basic(EnvI& env, Expression* e) { std::ostringstream oss; Printer p(oss,0,false); if (SetLit* sl = e->dyn_cast()) { oss << "{ \"set\" : ["; if (IntSetVal* isv = sl->isv()) { bool first=true; for (IntSetRanges isr(isv); isr(); ++isr) { if (first) { first=false; } else { oss << ","; } if (isr.min()==isr.max()) { oss << isr.min(); } else { oss << "[" << isr.min() << "," << isr.max() << "]"; } } } else if (FloatSetVal* fsv = sl->fsv()) { bool first=true; for (FloatSetRanges fsr(fsv); fsr(); ++fsr) { if (first) { first=false; } else { oss << ","; } if (fsr.min()==fsr.max()) { ppFloatVal(oss, fsr.min()); } else { oss << "["; ppFloatVal(oss, fsr.min()); oss << ","; ppFloatVal(oss, fsr.max()); oss << "]"; } } } else { for (unsigned int i=0; iv().size(); i++) { p.print(sl->v()[i]); if (iv().size()-1) oss << ","; } } oss << "]}"; } else if (e == constants().absent) { oss << "null"; } else { p.print(e); } return oss.str(); } std::string b_show_json(EnvI& env, Call* call) { Expression* exp = call->arg(0); GCLock lock; Expression* e = eval_par(env,exp); if (e->type().isvar()) { std::ostringstream oss; Printer p(oss,0,false); p.print(e); return oss.str(); } else { if (ArrayLit* al = e->dyn_cast()) { std::vector dims(al->dims()-1); if (dims.size() != 0) { dims[0] = al->max(al->dims()-1)-al->min(al->dims()-1)+1; } for (int i=1; idims()-1; i++) { dims[i] = dims[i-1] * (al->max(al->dims()-1-i)-al->min(al->dims()-1-i)+1); } std::ostringstream oss; oss << "["; for (unsigned int i=0; isize(); i++) { for (unsigned int j=0; jsize()-1) oss << ", "; } oss << "]"; return oss.str(); } else { return b_show_json_basic(env, e); } } } Expression* b_outputJSON(EnvI& env, Call* call) { return createJSONOutput(env, false, false); } Expression* b_outputJSONParameters(EnvI& env, Call* call) { std::vector outputVars; outputVars.push_back(new StringLit(Location().introduce(), "{\n")); class JSONParVisitor : public ItemVisitor { protected: EnvI& e; std::vector& outputVars; bool first_var; public: JSONParVisitor(EnvI& e0, std::vector& outputVars0) : e(e0), outputVars(outputVars0), first_var(true) {} void vVarDeclI(VarDeclI* vdi) { VarDecl* vd = vdi->e(); if (vd->ann().contains(constants().ann.rhs_from_assignment)) { std::ostringstream s; if (first_var) { first_var = false; } else { s << ",\n"; } s << " \"" << vd->id()->str().str() << "\"" << " : "; StringLit* sl = new StringLit(Location().introduce(),s.str()); outputVars.push_back(sl); std::vector showArgs(1); showArgs[0] = vd->id(); Call* show = new Call(Location().introduce(),"showJSON",showArgs); show->type(Type::parstring()); FunctionI* fi = e.model->matchFn(e, show, false); assert(fi); show->decl(fi); outputVars.push_back(show); } } } jsonov(env, outputVars); iterItems(jsonov, env.model); outputVars.push_back(new StringLit(Location().introduce(), "\n}\n")); return new ArrayLit(Location().introduce(),outputVars); } std::string b_format(EnvI& env, Call* call) { int width = 0; int prec = -1; GCLock lock; Expression* e; if (call->n_args()>1) { width = static_cast(eval_int(env,call->arg(0)).toInt()); if (call->n_args()==2) { e = eval_par(env,call->arg(1)); } else { assert(call->n_args()==3); prec = static_cast(eval_int(env,call->arg(1)).toInt()); if (prec < 0) throw EvalError(env, call->arg(1)->loc(),"output precision cannot be negative"); e = eval_par(env,call->arg(2)); } } else { e = eval_par(env,call->arg(0)); } if (e->type() == Type::parint()) { long long int i = eval_int(env,e).toInt(); std::ostringstream formatted; if (width > 0) { formatted.width(width); } else if (width < 0) { formatted.width(-width); formatted.flags(std::ios::left); } if (prec != -1) formatted.precision(prec); formatted << i; return formatted.str(); } else if (e->type() == Type::parfloat()) { FloatVal i = eval_float(env,e); std::ostringstream formatted; if (width > 0) { formatted.width(width); } else if (width < 0) { formatted.width(-width); formatted.flags(std::ios::left); } formatted.setf(std::ios::fixed); formatted.precision(std::numeric_limits::digits10+2); if (prec != -1) formatted.precision(prec); formatted << i; return formatted.str(); } else { std::string s = show(env,e); if (prec >= 0 && prec < s.size()) s = s.substr(0,prec); std::ostringstream oss; if (s.size() < std::abs(width)) { int addLeft = width < 0 ? 0 : (width - static_cast(s.size())); if (addLeft < 0) addLeft = 0; int addRight = width < 0 ? (-width-static_cast(s.size())) : 0; if (addRight < 0) addRight = 0; for (int i=addLeft; i--;) oss << " "; oss << s; for (int i=addRight; i--;) oss << " "; return oss.str(); } else { return s; } } } std::string b_format_justify_string(EnvI& env, Call* call) { int width = 0; GCLock lock; Expression* e; width = static_cast(eval_int(env,call->arg(0)).toInt()); e = eval_par(env,call->arg(1)); std::string s = eval_string(env,e); std::ostringstream oss; if (s.size() < std::abs(width)) { int addLeft = width < 0 ? 0 : (width - static_cast(s.size())); if (addLeft < 0) addLeft = 0; int addRight = width < 0 ? (-width-static_cast(s.size())) : 0; if (addRight < 0) addRight = 0; for (int i=addLeft; i--;) oss << " "; oss << s; for (int i=addRight; i--;) oss << " "; return oss.str(); } else { return s; } } std::string b_show_int(EnvI& env, Call* call) { assert(call->n_args()==2); GCLock lock; Expression* e = eval_par(env,call->arg(1)); std::ostringstream oss; if (IntLit* iv = e->dyn_cast()) { int justify = static_cast(eval_int(env,call->arg(0)).toInt()); std::ostringstream oss_length; oss_length << iv->v(); int iv_length = static_cast(oss_length.str().size()); int addLeft = justify < 0 ? 0 : (justify - iv_length); if (addLeft < 0) addLeft = 0; int addRight = justify < 0 ? (-justify-iv_length) : 0; if (addRight < 0) addRight = 0; for (int i=addLeft; i--;) oss << " "; oss << iv->v(); for (int i=addRight; i--;) oss << " "; } else { Printer p(oss,0,false); p.print(e); } return oss.str(); } std::string b_show_float(EnvI& env, Call* call) { assert(call->n_args()==3); GCLock lock; Expression* e = eval_par(env,call->arg(2)); std::ostringstream oss; if (FloatLit* fv = e->dyn_cast()) { int justify = static_cast(eval_int(env,call->arg(0)).toInt()); int prec = static_cast(eval_int(env,call->arg(1)).toInt()); if (prec < 0) throw EvalError(env, call->arg(1)->loc(), "number of digits in show_float cannot be negative"); std::ostringstream oss_length; oss_length << std::setprecision(prec) << std::fixed << fv->v(); int fv_length = static_cast(oss_length.str().size()); int addLeft = justify < 0 ? 0 : (justify - fv_length); if (addLeft < 0) addLeft = 0; int addRight = justify < 0 ? (-justify-fv_length) : 0; if (addRight < 0) addRight = 0; for (int i=addLeft; i--;) oss << " "; oss << std::setprecision(prec) << std::fixed << fv->v(); for (int i=addRight; i--;) oss << " "; } else { Printer p(oss,0,false); p.print(e); } return oss.str(); } std::string b_file_path(EnvI&, Call* call) { return FileUtils::file_path(call->loc().filename().str()); } std::string b_concat(EnvI& env, Call* call) { assert(call->n_args()==1); GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); std::ostringstream oss; for (unsigned int i=0; isize(); i++) { oss << eval_string(env,(*al)[i]); } return oss.str(); } std::string b_join(EnvI& env, Call* call) { assert(call->n_args()==2); std::string sep = eval_string(env,call->arg(0)); GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(1)); std::ostringstream oss; for (unsigned int i=0; isize(); i++) { oss << eval_string(env,(*al)[i]); if (isize()-1) oss << sep; } return oss.str(); } IntSetVal* b_array_union(EnvI& env, Call* call) { assert(call->n_args()==1); ArrayLit* al = eval_array_lit(env,call->arg(0)); if (al->size()==0) return IntSetVal::a(); IntSetVal* isv = eval_intset(env,(*al)[0]); for (unsigned int i=0; isize(); i++) { IntSetRanges i0(isv); IntSetRanges i1(eval_intset(env,(*al)[i])); Ranges::Union u(i0,i1); isv = IntSetVal::ai(u); } return isv; } IntSetVal* b_array_intersect(EnvI& env, Call* call) { assert(call->n_args()==1); ArrayLit* al = eval_array_lit(env,call->arg(0)); std::vector ranges; if (al->size() > 0) { IntSetVal* i0 = eval_intset(env,(*al)[0]); if (i0->size() > 0) { IntSetRanges i0r(i0); IntVal min = i0r.min(); while (i0r()) { // Initialize with last interval IntVal max = i0r.max(); // Intersect with all other intervals restart: for (int j=al->size(); j--;) { IntSetRanges ij(eval_intset(env,(*al)[j])); // Skip intervals that are too small while (ij() && (ij.max() < min)) ++ij; if (!ij()) goto done; if (ij.min() > max) { min=ij.min(); max=ij.max(); goto restart; } // Now the intervals overlap if (min < ij.min()) min = ij.min(); if (max > ij.max()) max = ij.max(); } ranges.push_back(IntSetVal::Range(min,max)); // The next interval must be at least two elements away min = max + 2; } done: return IntSetVal::a(ranges); } else { return IntSetVal::a(); } } else { return IntSetVal::a(); } } Expression* b_sort_by_int(EnvI& env, Call* call) { assert(call->n_args()==2); ArrayLit* al = eval_array_lit(env,call->arg(0)); ArrayLit* order_e = eval_array_lit(env,call->arg(1)); std::vector order(order_e->size()); std::vector a(order_e->size()); for (unsigned int i=0; i& order; Ord(std::vector& order0) : order(order0) {} bool operator()(int i, int j) { return order[i] < order[j]; } } _ord(order); std::stable_sort(a.begin(), a.end(), _ord); std::vector sorted(a.size()); for (unsigned int i=static_cast(sorted.size()); i--;) sorted[i] = (*al)[a[i]]; ArrayLit* al_sorted = new ArrayLit(al->loc(), sorted); al_sorted->type(al->type()); return al_sorted; } Expression* b_sort_by_float(EnvI& env, Call* call) { assert(call->n_args()==2); ArrayLit* al = eval_array_lit(env,call->arg(0)); ArrayLit* order_e = eval_array_lit(env,call->arg(1)); std::vector order(order_e->size()); std::vector a(order_e->size()); for (unsigned int i=0; i& order; Ord(std::vector& order0) : order(order0) {} bool operator()(int i, int j) { return order[i] < order[j]; } } _ord(order); std::stable_sort(a.begin(), a.end(), _ord); std::vector sorted(a.size()); for (unsigned int i=static_cast(sorted.size()); i--;) sorted[i] = (*al)[a[i]]; ArrayLit* al_sorted = new ArrayLit(al->loc(), sorted); al_sorted->type(al->type()); return al_sorted; } Expression* b_sort(EnvI& env, Call* call) { assert(call->n_args()==1); ArrayLit* al = eval_array_lit(env,call->arg(0)); std::vector sorted(al->size()); for (unsigned int i=static_cast(sorted.size()); i--;) sorted[i] = (*al)[i]; struct Ord { EnvI& env; Ord(EnvI& env0) : env(env0) {} bool operator()(Expression* e0, Expression* e1) { switch (e0->type().bt()) { case Type::BT_INT: return eval_int(env,e0) < eval_int(env,e1); case Type::BT_BOOL: return eval_bool(env,e0) < eval_bool(env,e1); case Type::BT_FLOAT: return eval_float(env,e0) < eval_float(env,e1); default: throw EvalError(env, e0->loc(), "unsupported type for sorting"); } } } _ord(env); std::sort(sorted.begin(),sorted.end(),_ord); ArrayLit* al_sorted = new ArrayLit(al->loc(), sorted); al_sorted->type(al->type()); return al_sorted; } Expression* b_inverse(EnvI& env, Call* call) { assert(call->n_args()==1); ArrayLit* al = eval_array_lit(env,call->arg(0)); if (al->size()==0) return al; int min_idx = al->min(0); std::vector ivs(al->size()); IntVal minVal = eval_int(env, (*al)[0]); IntVal maxVal = minVal; ivs[0] = minVal; for (unsigned int i=1; isize(); i++) { IntVal ii = eval_int(env, (*al)[i]); ivs[i] = ii; minVal = std::min(minVal, ii); maxVal = std::max(maxVal, ii); } if (maxVal-minVal+1 != al->size()) { throw ResultUndefinedError(env, call->loc(), "inverse on non-contiguous set of values is undefined"); } std::vector inv(al->size()); std::vector used(al->size()); for (unsigned int i=0; iloc(), "inverse on non-contiguous set of values is undefined"); } } ArrayLit* al_inv = new ArrayLit(al->loc(), inv, {{minVal.toInt(),maxVal.toInt()}}); al_inv->type(al->type()); return al_inv; } Expression* b_set_to_ranges_int(EnvI& env, Call* call) { assert(call->n_args()==1); IntSetVal* isv = eval_intset(env, call->arg(0)); std::vector v(isv->size()*2); for (unsigned int i=0; isize(); i++) { v[2*i] = IntLit::a(isv->min(i)); v[2*i+1] = IntLit::a(isv->max(i)); } ArrayLit* al = new ArrayLit(call->loc().introduce(), v); al->type(Type::parint(1)); return al; } Expression* b_set_to_ranges_float(EnvI& env, Call* call) { assert(call->n_args()==1); FloatSetVal* fsv = eval_floatset(env, call->arg(0)); std::vector v(fsv->size()*2); for (unsigned int i=0; isize(); i++) { v[2*i] = FloatLit::a(fsv->min(i)); v[2*i+1] = FloatLit::a(fsv->max(i)); } ArrayLit* al = new ArrayLit(call->loc().introduce(), v); al->type(Type::parfloat(1)); return al; } std::default_random_engine& rnd_generator(void) { // TODO: initiate with seed if given as annotation/in command line static std::default_random_engine g; return g; } FloatVal b_normal_float_float(EnvI& env, Call* call) { assert(call->n_args() ==2); const double mean = eval_float(env,call->arg(0)).toDouble(); const double stdv = eval_float(env,call->arg(1)).toDouble(); std::normal_distribution distribution(mean,stdv); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_normal_int_float(EnvI& env, Call* call) { assert(call->n_args() ==2); const double mean = double(eval_int(env,call->arg(0)).toInt()); const double stdv = eval_float(env,call->arg(1)).toDouble(); std::normal_distribution distribution(mean,stdv); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_uniform_float(EnvI& env, Call* call) { assert(call->n_args() == 2); const double lb = eval_float(env,call->arg(0)).toDouble(); const double ub = eval_float(env,call->arg(1)).toDouble(); if(lb > ub) { std::stringstream ssm; ssm << "lowerbound of uniform distribution \"" << lb << "\" is higher than its upperbound: " << ub; throw EvalError(env, call->arg(0)->loc(),ssm.str()); } std::uniform_real_distribution distribution(lb,ub); // return a sample from the distribution return distribution(rnd_generator()); } IntVal b_uniform_int(EnvI& env, Call* call) { assert(call->n_args() == 2); const long long int lb = eval_int(env,call->arg(0)).toInt(); const long long int ub = eval_int(env,call->arg(1)).toInt(); if(lb > ub) { std::stringstream ssm; ssm << "lowerbound of uniform distribution \"" << lb << "\" is higher than its upperbound: " << ub; throw EvalError(env, call->arg(0)->loc(),ssm.str()); } std::uniform_int_distribution distribution(lb,ub); // return a sample from the distribution return IntVal(distribution(rnd_generator())); } IntVal b_poisson_int(EnvI& env, Call* call) { assert(call->n_args() == 1); long long int mean = eval_int(env,call->arg(0)).toInt(); std::poisson_distribution distribution(mean); // return a sample from the distribution return IntVal(distribution(rnd_generator())); } IntVal b_poisson_float(EnvI& env, Call* call) { assert(call->n_args() == 1); double mean = eval_float(env,call->arg(0)).toDouble(); std::poisson_distribution distribution(mean); // return a sample from the distribution return IntVal(distribution(rnd_generator())); } FloatVal b_gamma_float_float(EnvI& env, Call* call) { assert(call->n_args() == 2); const double alpha = eval_float(env,call->arg(0)).toDouble(); const double beta = eval_float(env,call->arg(1)).toDouble(); std::gamma_distribution distribution(alpha,beta); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_gamma_int_float(EnvI& env, Call* call) { assert(call->n_args() == 2); const double alpha = eval_float(env,call->arg(0)).toDouble(); const double beta = eval_float(env,call->arg(1)).toDouble(); std::gamma_distribution distribution(alpha,beta); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_weibull_int_float(EnvI& env, Call* call) { assert(call->n_args() == 2); const double shape = double(eval_int(env,call->arg(0)).toInt()); if(shape < 0) { std::stringstream ssm; ssm << "The shape factor for the weibull distribution \"" << shape << "\" has to be greater than zero."; throw EvalError(env, call->arg(0)->loc(),ssm.str()); } const double scale = eval_float(env,call->arg(1)).toDouble(); if(scale < 0) { std::stringstream ssm; ssm << "The scale factor for the weibull distribution \"" << scale << "\" has to be greater than zero."; throw EvalError(env, call->arg(1)->loc(),ssm.str()); } std::weibull_distribution distribution(shape, scale); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_weibull_float_float(EnvI& env, Call* call) { assert(call->n_args() == 2); const double shape = eval_float(env,call->arg(0)).toDouble(); if(shape < 0) { std::stringstream ssm; ssm << "The shape factor for the weibull distribution \"" << shape << "\" has to be greater than zero."; throw EvalError(env, call->arg(0)->loc(),ssm.str()); } const double scale = eval_float(env,call->arg(1)).toDouble(); if(scale < 0) { std::stringstream ssm; ssm << "The scale factor for the weibull distribution \"" << scale << "\" has to be greater than zero."; throw EvalError(env, call->arg(1)->loc(),ssm.str()); } std::weibull_distribution distribution(shape, scale); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_exponential_float(EnvI& env, Call* call) { assert(call->n_args() == 1); const double lambda = eval_float(env,call->arg(0)).toDouble(); if(lambda < 0) { std::stringstream ssm; ssm << "The lambda-parameter for the exponential distribution function \"" << lambda << "\" has to be greater than zero."; throw EvalError(env, call->arg(0)->loc(),ssm.str()); } std::exponential_distribution distribution(lambda); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_exponential_int(EnvI& env, Call* call) { assert(call->n_args() == 1); const double lambda = double(eval_int(env,call->arg(0)).toInt()); if(lambda < 0) { std::stringstream ssm; ssm << "The lambda-parameter for the exponential distribution function \"" << lambda << "\" has to be greater than zero."; throw EvalError(env, call->arg(0)->loc(),ssm.str()); } std::exponential_distribution distribution(lambda); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_lognormal_float_float(EnvI& env, Call* call) { assert(call->n_args() ==2); const double mean = eval_float(env,call->arg(0)).toDouble(); const double stdv = eval_float(env,call->arg(1)).toDouble(); std::lognormal_distribution distribution(mean,stdv); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_lognormal_int_float(EnvI& env, Call* call) { assert(call->n_args() ==2); const double mean = double(eval_int(env,call->arg(0)).toInt()); const double stdv = eval_float(env,call->arg(1)).toDouble(); std::lognormal_distribution distribution(mean,stdv); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_chisquared_float(EnvI& env, Call* call) { assert(call->n_args() == 1); const double lambda = eval_float(env,call->arg(0)).toDouble(); std::exponential_distribution distribution(lambda); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_chisquared_int(EnvI& env, Call* call) { assert(call->n_args() == 1); const double lambda = double(eval_int(env,call->arg(0)).toInt()); std::exponential_distribution distribution(lambda); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_cauchy_float_float(EnvI& env, Call* call) { assert(call->n_args() ==2); const double mean = eval_float(env,call->arg(0)).toDouble(); const double scale = eval_float(env,call->arg(1)).toDouble(); std::cauchy_distribution distribution(mean,scale); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_cauchy_int_float(EnvI& env, Call* call) { assert(call->n_args() ==2); const double mean = double(eval_int(env,call->arg(0)).toInt()); const double scale = eval_float(env,call->arg(1)).toDouble(); std::cauchy_distribution distribution(mean,scale); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_fdistribution_float_float(EnvI& env, Call* call) { assert(call->n_args() ==2); const double d1 = eval_float(env,call->arg(0)).toDouble(); const double d2 = eval_float(env,call->arg(1)).toDouble(); std::fisher_f_distribution distribution(d1,d2); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_fdistribution_int_int(EnvI& env, Call* call) { assert(call->n_args() ==2); const double d1 = double(eval_int(env,call->arg(0)).toInt()); const double d2 = double(eval_int(env,call->arg(1)).toInt()); std::fisher_f_distribution distribution(d1,d2); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_tdistribution_float(EnvI& env, Call* call) { assert(call->n_args() == 1); const double sampleSize = eval_float(env,call->arg(0)).toDouble(); std::student_t_distribution distribution(sampleSize); // return a sample from the distribution return distribution(rnd_generator()); } FloatVal b_tdistribution_int(EnvI& env, Call* call) { assert(call->n_args() == 1); const double sampleSize = double(eval_int(env,call->arg(0)).toInt()); std::student_t_distribution distribution(sampleSize); // return a sample from the distribution return distribution(rnd_generator()); } IntVal b_discrete_distribution(EnvI& env, Call* call) { assert(call->n_args() == 1); GCLock lock; ArrayLit* al = eval_array_lit(env,call->arg(0)); if(al->dims() != 1) { std::stringstream ssm; ssm << "expecting 1-dimensional array of weights for discrete distribution instead of: " << *al << std::endl; throw EvalError(env, al->loc(), ssm.str()); } std::vector weights(al->size()); for(unsigned int i = 0; i < al->size(); i++) { weights[i] = eval_int(env,(*al)[i]).toInt(); } #ifdef _MSC_VER std::size_t i(0); std::discrete_distribution distribution(weights.size(), 0.0,1.0, [&weights,&i](double){ return weights[i++]; }); #else std::discrete_distribution distribution(weights.begin(), weights.end()); #endif // return a sample from the distribution IntVal iv = IntVal(distribution(rnd_generator())); return iv; } bool b_bernoulli(EnvI& env, Call* call) { assert(call->n_args() == 1); const double p = eval_float(env,call->arg(0)).toDouble(); std::bernoulli_distribution distribution(p); // return a sample from the distribution return distribution(rnd_generator()); } IntVal b_binomial(EnvI& env, Call* call) { assert(call->n_args() == 2); double t = double(eval_int(env,call->arg(0)).toInt()); double p = eval_float(env,call->arg(1)).toDouble(); std::binomial_distribution distribution(t,p); // return a sample from the distribution return IntVal(distribution(rnd_generator())); } FloatVal b_atan(EnvI& env, Call* call) { assert(call->n_args()==1); GCLock lock; FloatVal f = eval_float(env,call->arg(0)); return std::atan(f.toDouble()); } FloatVal b_cos(EnvI& env, Call* call) { assert(call->n_args()==1); GCLock lock; FloatVal f = eval_float(env,call->arg(0)); return std::cos(f.toDouble()); } FloatVal b_sin(EnvI& env, Call* call) { assert(call->n_args()==1); GCLock lock; FloatVal f = eval_float(env,call->arg(0)); return std::sin(f.toDouble()); } FloatVal b_asin(EnvI& env, Call* call) { assert(call->n_args()==1); GCLock lock; FloatVal f = eval_float(env,call->arg(0)); return std::asin(f.toDouble()); } FloatVal b_acos(EnvI& env, Call* call) { assert(call->n_args()==1); GCLock lock; FloatVal f = eval_float(env,call->arg(0)); return std::acos(f.toDouble()); } FloatVal b_tan(EnvI& env, Call* call) { assert(call->n_args()==1); GCLock lock; FloatVal f = eval_float(env,call->arg(0)); return std::tan(f.toDouble()); } IntVal b_to_enum(EnvI& env, Call* call) { assert(call->n_args()==2); IntSetVal* isv = eval_intset(env, call->arg(0)); IntVal v = eval_int(env, call->arg(1)); if (!isv->contains(v)) throw ResultUndefinedError(env, call->loc(), "value outside of enum range"); return v; } IntVal b_enum_next(EnvI& env, Call* call) { IntSetVal* isv = eval_intset(env, call->arg(0)); IntVal v = eval_int(env, call->arg(1)); if (!isv->contains(v+1)) throw ResultUndefinedError(env, call->loc(), "value outside of enum range"); return v+1; } IntVal b_enum_prev(EnvI& env, Call* call) { IntSetVal* isv = eval_intset(env, call->arg(0)); IntVal v = eval_int(env, call->arg(1)); if (!isv->contains(v-1)) throw ResultUndefinedError(env, call->loc(), "value outside of enum range"); return v-1; } IntVal b_mzn_compiler_version(EnvI&, Call*) { return atoi(MZN_VERSION_MAJOR)*10000+atoi(MZN_VERSION_MINOR)*1000+atoi(MZN_VERSION_PATCH); } Expression* b_slice(EnvI& env, Call* call) { ArrayLit* al = eval_array_lit(env,call->arg(0)); ArrayLit* slice = eval_array_lit(env,call->arg(1)); std::vector> newSlice(slice->size()); for (unsigned int i=0; isize(); i++) { IntSetVal* isv = eval_intset(env, (*slice)[i]); if (isv->size()==0) { newSlice[i] = std::pair(1,0); } else { if (isv->size()>1) throw ResultUndefinedError(env, call->loc(), "array slice must be contiguous"); int sl_min = isv->min().isFinite() ? static_cast(isv->min().toInt()) : al->min(i); int sl_max = isv->max().isFinite() ? static_cast(isv->max().toInt()) : al->max(i); if (sl_min < al->min(i) || sl_max > al->max(i)) throw ResultUndefinedError(env, call->loc(), "array slice out of bounds"); newSlice[i] = std::pair(sl_min, sl_max); } } std::vector> newDims(call->n_args()-2); for (unsigned int i=0; iarg(2+i)); if (isv->size()==0) { newDims[i] = std::pair(1,0); } else { newDims[i] = std::pair(static_cast(isv->min().toInt()), static_cast(isv->max().toInt())); } } ArrayLit* ret = new ArrayLit(al->loc(), al, newDims, newSlice); ret->type(call->type()); return ret; } Expression* b_regular_from_string(EnvI& env, Call* call) { #ifdef HAS_GECODE using namespace Gecode; ArrayLit* vars = eval_array_lit(env, call->arg(0)); std::string expr = eval_string(env, call->arg(1)); IntSetVal* dom; if (vars->size()==0) { dom = IntSetVal::a(); } else { dom = b_dom_varint(env,(*vars)[0]); for (unsigned int i=1; i < vars->size(); i++) { IntSetRanges isr(dom); IntSetRanges r(b_dom_varint(env,(*vars)[i])); Ranges::Union u(isr,r); dom = IntSetVal::ai(u); } } int card = dom->max().toInt() - dom->min().toInt() + 1; int offset = 1 - dom->min().toInt(); std::unique_ptr regex; try { regex = regex_from_string(expr, *dom, env.reverseEnum); } catch (const std::exception& e) { throw SyntaxError(call->arg(1)->loc(), e.what()); } DFA dfa = DFA(*regex); std::vector< std::vector > reg_trans( dfa.n_states(), std::vector( card, IntLit::a(IntVal(0)) ) ); DFA::Transitions trans(dfa); while (trans()) { // std::cerr << trans.i_state() + 1 << " -- " << trans.symbol() << " --> " << trans.o_state() + 1 << "\n"; if (trans.symbol() >= dom->min().toInt() && trans.symbol() <= dom->max().toInt()) { reg_trans[trans.i_state()][trans.symbol()+offset-1] = IntLit::a(IntVal(trans.o_state()+1)); } ++trans; } std::vector args(6); if (offset == 0) { args[0] = vars; // x } else { std::vector nvars(vars->size()); IntLit* loffset = IntLit::a(IntVal(offset)); for (int i = 0; i < nvars.size(); ++i) { nvars[i] = new BinOp(call->loc().introduce(), (*vars)[i], BOT_PLUS, loffset); nvars[i]->type(Type::varint()); } args[0] = new ArrayLit(call->loc().introduce(), nvars); // x args[0]->type(Type::varint(1)); } args[1] = IntLit::a(IntVal(dfa.n_states())); // Q args[1]->type(Type::parint()); args[2] = IntLit::a(IntVal(card));// S args[2]->type(Type::parint()); args[3] = new ArrayLit(call->loc().introduce(), reg_trans); // d args[3]->type(Type::parint(2)); args[4] = IntLit::a(IntVal(1)); // q0 args[4]->type(Type::parint()); args[5] = new SetLit(call->loc().introduce(), IntSetVal::a(IntVal(dfa.final_fst()+1), IntVal(dfa.final_lst()))); // F args[5]->type(Type::parsetint()); auto nc = new Call(call->loc().introduce(), "regular", args); nc->type(Type::varbool()); return nc; #else throw FlatteningError(env, call->loc(), "MiniZinc was compiled without built-in Gecode, cannot parse regular expression"); #endif } void registerBuiltins(Env& e) { EnvI& env = e.envi(); Model* m = env.model; std::vector t_intint(2); t_intint[0] = Type::parint(); t_intint[1] = Type::parint(); std::vector t_intarray(1); t_intarray[0] = Type::parint(-1); GCLock lock; rb(env, m, ASTString("min"), t_intint, b_int_min); rb(env, m, ASTString("min"), t_intarray, b_int_min); rb(env, m, ASTString("max"), t_intint, b_int_max); rb(env, m, ASTString("max"), t_intarray, b_int_max); rb(env, m, constants().ids.sum, t_intarray, b_sum_int); rb(env, m, ASTString("product"), t_intarray, b_product_int); rb(env, m, ASTString("pow"), t_intint, b_pow_int); { std::vector t(2); t[0] = Type::top(-1); t[1] = Type::top(-1); rb(env, m, ASTString("index_sets_agree"), t, b_index_sets_agree); } { std::vector t_anyarray1(1); t_anyarray1[0] = Type::optvartop(1); rb(env, m, ASTString("index_set"), t_anyarray1, b_index_set1); } { std::vector t_anyarray2(1); t_anyarray2[0] = Type::optvartop(2); rb(env, m, ASTString("index_set_1of2"), t_anyarray2, b_index_set1); rb(env, m, ASTString("index_set_2of2"), t_anyarray2, b_index_set2); } { std::vector t_anyarray3(1); t_anyarray3[0] = Type::optvartop(3); rb(env, m, ASTString("index_set_1of3"), t_anyarray3, b_index_set1); rb(env, m, ASTString("index_set_2of3"), t_anyarray3, b_index_set2); rb(env, m, ASTString("index_set_3of3"), t_anyarray3, b_index_set3); } { std::vector t_anyarray4(1); t_anyarray4[0] = Type::optvartop(4); rb(env, m, ASTString("index_set_1of4"), t_anyarray4, b_index_set1); rb(env, m, ASTString("index_set_2of4"), t_anyarray4, b_index_set2); rb(env, m, ASTString("index_set_3of4"), t_anyarray4, b_index_set3); rb(env, m, ASTString("index_set_4of4"), t_anyarray4, b_index_set4); } { std::vector t_anyarray5(1); t_anyarray5[0] = Type::optvartop(5); rb(env, m, ASTString("index_set_1of5"), t_anyarray5, b_index_set1); rb(env, m, ASTString("index_set_2of5"), t_anyarray5, b_index_set2); rb(env, m, ASTString("index_set_3of5"), t_anyarray5, b_index_set3); rb(env, m, ASTString("index_set_4of5"), t_anyarray5, b_index_set4); rb(env, m, ASTString("index_set_5of5"), t_anyarray5, b_index_set5); } { std::vector t_anyarray6(1); t_anyarray6[0] = Type::optvartop(6); rb(env, m, ASTString("index_set_1of6"), t_anyarray6, b_index_set1); rb(env, m, ASTString("index_set_2of6"), t_anyarray6, b_index_set2); rb(env, m, ASTString("index_set_3of6"), t_anyarray6, b_index_set3); rb(env, m, ASTString("index_set_4of6"), t_anyarray6, b_index_set4); rb(env, m, ASTString("index_set_5of6"), t_anyarray6, b_index_set5); rb(env, m, ASTString("index_set_6of6"), t_anyarray6, b_index_set6); } { std::vector t_arrayXd(1); t_arrayXd[0] = Type::top(-1); rb(env, m, ASTString("array1d"), t_arrayXd, b_array1d_list); t_arrayXd[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("array1d"), t_arrayXd, b_array1d_list); t_arrayXd[0] = Type::vartop(-1); rb(env, m, ASTString("array1d"), t_arrayXd, b_array1d_list); t_arrayXd[0] = Type::optvartop(-1); rb(env, m, ASTString("array1d"), t_arrayXd, b_array1d_list); } { std::vector t_arrayXd(2); t_arrayXd[0] = Type::parsetint(); t_arrayXd[1] = Type::top(-1); rb(env, m, ASTString("array1d"), t_arrayXd, b_array1d); t_arrayXd[1].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("array1d"), t_arrayXd, b_array1d); t_arrayXd[1] = Type::vartop(-1); rb(env, m, ASTString("array1d"), t_arrayXd, b_array1d); t_arrayXd[1] = Type::optvartop(-1); rb(env, m, ASTString("array1d"), t_arrayXd, b_array1d); } { std::vector t_arrayXd(2); t_arrayXd[0] = Type::optvartop(-1); t_arrayXd[1] = Type::top(-1); rb(env, m, ASTString("arrayXd"), t_arrayXd, b_arrayXd); t_arrayXd[1].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("arrayXd"), t_arrayXd, b_arrayXd); t_arrayXd[1] = Type::vartop(-1); rb(env, m, ASTString("arrayXd"), t_arrayXd, b_arrayXd); t_arrayXd[1] = Type::optvartop(-1); rb(env, m, ASTString("arrayXd"), t_arrayXd, b_arrayXd); } { std::vector t_arrayXd(3); t_arrayXd[0] = Type::parsetint(); t_arrayXd[1] = Type::parsetint(); t_arrayXd[2] = Type::top(-1); rb(env, m, ASTString("array2d"), t_arrayXd, b_array2d); t_arrayXd[2].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("array2d"), t_arrayXd, b_array2d); t_arrayXd[2] = Type::vartop(-1); rb(env, m, ASTString("array2d"), t_arrayXd, b_array2d); t_arrayXd[2] = Type::optvartop(-1); rb(env, m, ASTString("array2d"), t_arrayXd, b_array2d); } { std::vector t_arrayXd(4); t_arrayXd[0] = Type::parsetint(); t_arrayXd[1] = Type::parsetint(); t_arrayXd[2] = Type::parsetint(); t_arrayXd[3] = Type::top(-1); rb(env, m, ASTString("array3d"), t_arrayXd, b_array3d); t_arrayXd[3].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("array3d"), t_arrayXd, b_array3d); t_arrayXd[3] = Type::vartop(-1); rb(env, m, ASTString("array3d"), t_arrayXd, b_array3d); t_arrayXd[3] = Type::optvartop(-1); rb(env, m, ASTString("array3d"), t_arrayXd, b_array3d); } { std::vector t_arrayXd(5); t_arrayXd[0] = Type::parsetint(); t_arrayXd[1] = Type::parsetint(); t_arrayXd[2] = Type::parsetint(); t_arrayXd[3] = Type::parsetint(); t_arrayXd[4] = Type::top(-1); rb(env, m, ASTString("array4d"), t_arrayXd, b_array4d); t_arrayXd[4].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("array4d"), t_arrayXd, b_array4d); t_arrayXd[4] = Type::vartop(-1); rb(env, m, ASTString("array4d"), t_arrayXd, b_array4d); t_arrayXd[4] = Type::optvartop(-1); rb(env, m, ASTString("array4d"), t_arrayXd, b_array4d); } { std::vector t_arrayXd(6); t_arrayXd[0] = Type::parsetint(); t_arrayXd[1] = Type::parsetint(); t_arrayXd[2] = Type::parsetint(); t_arrayXd[3] = Type::parsetint(); t_arrayXd[4] = Type::parsetint(); t_arrayXd[5] = Type::top(-1); rb(env, m, ASTString("array5d"), t_arrayXd, b_array5d); t_arrayXd[5].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("array5d"), t_arrayXd, b_array5d); t_arrayXd[5] = Type::vartop(-1); rb(env, m, ASTString("array5d"), t_arrayXd, b_array5d); t_arrayXd[5] = Type::optvartop(-1); rb(env, m, ASTString("array5d"), t_arrayXd, b_array5d); } { std::vector t_arrayXd(7); t_arrayXd[0] = Type::parsetint(); t_arrayXd[1] = Type::parsetint(); t_arrayXd[2] = Type::parsetint(); t_arrayXd[3] = Type::parsetint(); t_arrayXd[4] = Type::parsetint(); t_arrayXd[5] = Type::parsetint(); t_arrayXd[6] = Type::top(-1); rb(env, m, ASTString("array6d"), t_arrayXd, b_array6d); t_arrayXd[6].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("array6d"), t_arrayXd, b_array6d); t_arrayXd[6] = Type::vartop(-1); rb(env, m, ASTString("array6d"), t_arrayXd, b_array6d); t_arrayXd[6] = Type::optvartop(-1); rb(env, m, ASTString("array6d"), t_arrayXd, b_array6d); } { std::vector stv(3); stv[0] = Type::partop(-1); stv[1] = Type::parsetint(1); stv[2] = Type::parsetint(); rb(env, m, ASTString("slice_1d"), stv, b_slice); stv[0] = Type::vartop(-1); rb(env, m, ASTString("slice_1d"), stv, b_slice); stv[0] = Type::optvartop(-1); rb(env, m, ASTString("slice_1d"), stv, b_slice); stv[0] = Type::optpartop(-1); rb(env, m, ASTString("slice_1d"), stv, b_slice); stv.push_back(Type::parsetint()); stv[0] = Type::partop(-1); rb(env, m, ASTString("slice_2d"), stv, b_slice); stv[0] = Type::vartop(-1); rb(env, m, ASTString("slice_2d"), stv, b_slice); stv[0] = Type::optvartop(-1); rb(env, m, ASTString("slice_2d"), stv, b_slice); stv[0] = Type::optpartop(-1); rb(env, m, ASTString("slice_2d"), stv, b_slice); stv.push_back(Type::parsetint()); stv[0] = Type::partop(-1); rb(env, m, ASTString("slice_3d"), stv, b_slice); stv[0] = Type::vartop(-1); rb(env, m, ASTString("slice_3d"), stv, b_slice); stv[0] = Type::optvartop(-1); rb(env, m, ASTString("slice_3d"), stv, b_slice); stv[0] = Type::optpartop(-1); rb(env, m, ASTString("slice_3d"), stv, b_slice); stv.push_back(Type::parsetint()); stv[0] = Type::partop(-1); rb(env, m, ASTString("slice_4d"), stv, b_slice); stv[0] = Type::vartop(-1); rb(env, m, ASTString("slice_4d"), stv, b_slice); stv[0] = Type::optvartop(-1); rb(env, m, ASTString("slice_4d"), stv, b_slice); stv[0] = Type::optpartop(-1); rb(env, m, ASTString("slice_4d"), stv, b_slice); stv.push_back(Type::parsetint()); stv[0] = Type::partop(-1); rb(env, m, ASTString("slice_5d"), stv, b_slice); stv[0] = Type::vartop(-1); rb(env, m, ASTString("slice_5d"), stv, b_slice); stv[0] = Type::optvartop(-1); rb(env, m, ASTString("slice_5d"), stv, b_slice); stv[0] = Type::optpartop(-1); rb(env, m, ASTString("slice_5d"), stv, b_slice); stv.push_back(Type::parsetint()); stv[0] = Type::partop(-1); rb(env, m, ASTString("slice_6d"), stv, b_slice); stv[0] = Type::vartop(-1); rb(env, m, ASTString("slice_6d"), stv, b_slice); stv[0] = Type::optvartop(-1); rb(env, m, ASTString("slice_6d"), stv, b_slice); stv[0] = Type::optpartop(-1); rb(env, m, ASTString("slice_6d"), stv, b_slice); } { std::vector t(2); t[0] = Type::parbool(); t[1] = Type::parstring(); rb(env, m, constants().ids.assert, t, b_assert_bool); } { std::vector t(3); t[0] = Type::parbool(); t[1] = Type::parstring(); t[2] = Type::top(); rb(env, m, constants().ids.assert, t, b_assert); t[2] = Type::vartop(); rb(env, m, constants().ids.assert, t, b_assert); t[2] = Type::optvartop(); rb(env, m, constants().ids.assert, t, b_assert); t[2] = Type::top(-1); rb(env, m, constants().ids.assert, t, b_assert); t[2] = Type::vartop(-1); rb(env, m, constants().ids.assert, t, b_assert); t[2] = Type::optvartop(-1); rb(env, m, constants().ids.assert, t, b_assert); } { std::vector t(4); t[0] = Type::parstring(); t[1] = Type::parstring(); t[2] = Type::parstring(); t[3] = Type::top(); rb(env, m, constants().ids.mzn_deprecate, t, b_mzn_deprecate); t[3] = Type::vartop(); rb(env, m, constants().ids.mzn_deprecate, t, b_mzn_deprecate); t[3] = Type::optvartop(); rb(env, m, constants().ids.mzn_deprecate, t, b_mzn_deprecate); t[3] = Type::top(-1); rb(env, m, constants().ids.mzn_deprecate, t, b_mzn_deprecate); t[3] = Type::vartop(-1); rb(env, m, constants().ids.mzn_deprecate, t, b_mzn_deprecate); t[3] = Type::optvartop(-1); rb(env, m, constants().ids.mzn_deprecate, t, b_mzn_deprecate); } { std::vector t(1); t[0] = Type::parstring(); rb(env, m, ASTString("abort"), t, b_abort); rb(env, m, constants().ids.trace, t, b_trace); rb(env, m, ASTString("trace_stdout"), t, b_trace_stdout); } { std::vector t(2); t[0] = Type::parstring(); t[1] = Type::top(); rb(env, m, constants().ids.trace, t, b_trace); rb(env, m, ASTString("trace_stdout"), t, b_trace_stdout); t[1] = Type::vartop(); rb(env, m, constants().ids.trace, t, b_trace); rb(env, m, ASTString("trace_stdout"), t, b_trace_stdout); t[1] = Type::optvartop(); rb(env, m, constants().ids.trace, t, b_trace); rb(env, m, ASTString("trace_stdout"), t, b_trace_stdout); } { rb(env, m, ASTString("mzn_in_redundant_constraint"), std::vector(), b_in_redundant_constraint); } { std::vector t_length(1); t_length[0] = Type::optvartop(-1); rb(env, m, ASTString("length"), t_length, b_length); } { std::vector t(1); t[0] = Type::parbool(); rb(env, m, constants().ids.bool2int, t, b_bool2int); } { std::vector t(1); t[0] = Type::parbool(-1); rb(env, m, constants().ids.forall, t, b_forall_par); rb(env, m, constants().ids.exists, t, b_exists_par); rb(env, m, ASTString("xorall"), t, b_xorall_par); rb(env, m, ASTString("iffall"), t, b_iffall_par); } { std::vector t(2); t[0] = Type::parbool(-1); t[1] = Type::parbool(-1); rb(env, m, constants().ids.clause, t, b_clause_par); } { std::vector t(1); t[0] = Type::varsetint(); rb(env, m, ASTString("ub"), t, b_ub_set); rb(env, m, ASTString("lb"), t, b_lb_set); } { std::vector t(1); t[0] = Type::varsetint(1); rb(env, m, ASTString("ub_array"), t, b_array_ub_set); } { std::vector t(1); t[0] = Type::varint(); rb(env, m, ASTString("dom"), t, b_dom_varint); } { std::vector t(1); t[0] = Type::varint(-1); rb(env, m, ASTString("dom_array"), t, b_dom_array); rb(env, m, ASTString("dom_bounds_array"), t, b_dom_bounds_array); } { std::vector t(1); t[0] = Type::parsetint(); rb(env, m, ASTString("min"), t, b_min_parsetint); } { std::vector t(1); t[0] = Type::parsetint(); rb(env, m, ASTString("max"), t, b_max_parsetint); } { std::vector t(1); t[0] = Type::varint(); t[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("lb"), t, b_lb_varoptint); } { std::vector t(1); t[0] = Type::varint(); t[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("ub"), t, b_ub_varoptint); } { std::vector t(1); t[0] = Type::varint(); rb(env, m, ASTString("lb"), t, b_lb_varoptint); } { std::vector t(1); t[0] = Type::varint(); rb(env, m, ASTString("ub"), t, b_ub_varoptint); } { std::vector t(1); t[0] = Type::varint(-1); t[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("lb_array"), t, b_array_lb_int); } { std::vector t(1); t[0] = Type::varint(-1); t[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("ub_array"), t, b_array_ub_int); } { std::vector t(1); t[0] = Type::varfloat(); t[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("lb"), t, b_lb_varoptfloat); } { std::vector t(1); t[0] = Type::varfloat(); t[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("ub"), t, b_ub_varoptfloat); } { std::vector t(1); t[0] = Type::varfloat(); rb(env, m, ASTString("lb"), t, b_lb_varoptfloat); } { std::vector t(1); t[0] = Type::varfloat(); rb(env, m, ASTString("ub"), t, b_ub_varoptfloat); } { std::vector t(1); t[0] = Type::varfloat(-1); t[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("lb_array"), t, b_array_lb_float); } { std::vector t(1); t[0] = Type::varfloat(-1); t[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("ub_array"), t, b_array_ub_float); } { std::vector t(1); t[0] = Type::parsetint(); rb(env, m, ASTString("card"), t, b_card); } { std::vector t(1); t[0] = Type::parsetint(); rb(env, m, ASTString("set_to_ranges"), t, b_set_to_ranges_int); t[0] = Type::parsetfloat(); rb(env, m, ASTString("set_to_ranges"), t, b_set_to_ranges_float); } { std::vector t(1); t[0] = Type::parint(); rb(env, m, ASTString("abs"), t, b_abs_int); t[0] = Type::parfloat(); rb(env, m, ASTString("abs"), t, b_abs_float); } { std::vector t(1); t[0] = Type::varint(); rb(env, m, ASTString("has_bounds"), t, b_has_bounds_int); } { std::vector t(1); t[0] = Type::varfloat(); rb(env, m, ASTString("has_bounds"), t, b_has_bounds_float); } { std::vector t(1); t[0] = Type::varsetint(); rb(env, m, ASTString("has_ub_set"), t, b_has_ub_set); } { std::vector t(1); t[0] = Type::optvartop(); rb(env, m, ASTString("is_fixed"), t, b_is_fixed); t[0] = Type::varsetint(); rb(env, m, ASTString("is_fixed"), t, b_is_fixed); Type setoftop; setoftop.bt(Type::BT_TOP); setoftop.st(Type::ST_SET); setoftop.ti(Type::TI_PAR); setoftop.ot(Type::OT_PRESENT); t[0] = setoftop; rb(env, m, ASTString("is_fixed"), t, b_is_fixed); } { std::vector t(1); t[0] = Type::optvartop(-1); rb(env, m, ASTString("is_fixed"), t, b_is_fixed_array); } { std::vector t(1); t[0] = Type::optvartop(); rb(env, m, ASTString("fix"), t, b_fix_bool); rb(env, m, ASTString("fix"), t, b_fix_int); rb(env, m, ASTString("fix"), t, b_fix_set); rb(env, m, ASTString("fix"), t, b_fix_float); } { std::vector t(1); t[0] = Type::optvartop(1); rb(env, m, ASTString("fix"), t, b_fix_array); } { std::vector t(1); t[0] = Type::parint(); rb(env, m, ASTString("int2float"), t, b_int2float); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("ceil"), t, b_ceil); rb(env, m, ASTString("floor"), t, b_floor); rb(env, m, ASTString("round"), t, b_round); rb(env, m, ASTString("log10"), t, b_log10); rb(env, m, ASTString("log2"), t, b_log2); rb(env, m, ASTString("ln"), t, b_ln); rb(env, m, ASTString("exp"), t, b_exp); rb(env, m, ASTString("sqrt"), t, b_sqrt); t.push_back(Type::parfloat()); rb(env, m, ASTString("log"), t, b_log); rb(env, m, ASTString("pow"), t, b_pow); } { std::vector t(1); t[0] = Type::parfloat(1); rb(env, m, constants().ids.sum, t, b_sum_float); rb(env, m, ASTString("product"), t, b_product_float); } { std::vector t(1); t[0] = Type::parfloat(1); rb(env, m, ASTString("min"), t, b_float_min); rb(env, m, ASTString("max"), t, b_float_max); t[0] = Type::parfloat(); t.push_back(Type::parfloat()); rb(env, m, ASTString("min"), t, b_float_min); rb(env, m, ASTString("max"), t, b_float_max); } { std::vector t(1); t[0] = Type::parsetint(); rb(env, m, ASTString("set2array"), t, b_set2array); } { std::vector t(1); t[0] = Type::parstring(); rb(env, m, ASTString("string_length"), t, b_string_length); } { rb(env, m, ASTString("file_path"), std::vector(), b_file_path); } { std::vector t(1); t[0] = Type::vartop(); rb(env, m, ASTString("show"), t, b_show); rb(env, m, ASTString("showJSON"), t, b_show_json); t[0] = Type::vartop(); t[0].st(Type::ST_SET); t[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("show"), t, b_show); rb(env, m, ASTString("showJSON"), t, b_show_json); t[0] = Type::vartop(-1); rb(env, m, ASTString("show"), t, b_show); rb(env, m, ASTString("showJSON"), t, b_show_json); } { std::vector t(1); t[0] = Type::parstring(); rb(env, m, ASTString("showDznId"), t, b_showDznId); } { std::vector t(3); t[0] = t[1] = Type::parint(); t[2] = Type::vartop(); rb(env, m, ASTString("format"), t, b_format); t[2] = Type::vartop(); t[2].st(Type::ST_SET); t[2].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("format"), t, b_format); t[2] = Type::vartop(-1); rb(env, m, ASTString("format"), t, b_format); } { std::vector t(2); t[0] = Type::parint(); t[1] = Type::vartop(); rb(env, m, ASTString("format"), t, b_format); t[1] = Type::vartop(); t[1].st(Type::ST_SET); t[1].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("format"), t, b_format); t[1] = Type::vartop(-1); rb(env, m, ASTString("format"), t, b_format); t[1] = Type::parstring(); rb(env, m, ASTString("format_justify_string"), t, b_format_justify_string); } { std::vector t; rb(env, m, ASTString("outputJSON"), t, b_outputJSON); rb(env, m, ASTString("outputJSONParameters"), t, b_outputJSONParameters); } { std::vector t(2); t[0] = Type::parint(); t[1] = Type::varint(); rb(env, m, ASTString("show_int"), t, b_show_int); } { std::vector t(3); t[0] = Type::parint(); t[1] = Type::parint(); t[2] = Type::varfloat(); rb(env, m, ASTString("show_float"), t, b_show_float); } { std::vector t(1); t[0] = Type::parstring(1); rb(env, m, ASTString("concat"), t, b_concat); } { std::vector t(2); t[0] = Type::parstring(); t[1] = Type::parstring(1); rb(env, m, ASTString("join"), t, b_join); } { std::vector t(2); t[0] = Type::varint(); t[1] = Type::varint(); rb(env, m, ASTString("compute_div_bounds"), t, b_compute_div_bounds); } { std::vector t(1); t[0] = Type::parsetint(1); rb(env, m, ASTString("array_intersect"), t, b_array_intersect); rb(env, m, ASTString("array_union"), t, b_array_union); } { std::vector t(1); t[0] = Type::parint(); t[0].ot(Type::OT_OPTIONAL); t[0].bt(Type::BT_TOP); rb(env, m, ASTString("occurs"), t, b_occurs); rb(env, m, ASTString("deopt"), t, b_deopt_expr); t[0].bt(Type::BT_INT); rb(env, m, ASTString("deopt"), t, b_deopt_int); t[0].bt(Type::BT_BOOL); rb(env, m, ASTString("deopt"), t, b_deopt_bool); t[0].bt(Type::BT_FLOAT); rb(env, m, ASTString("deopt"), t, b_deopt_float); t[0].bt(Type::BT_STRING); rb(env, m, ASTString("deopt"), t, b_deopt_string); t[0].bt(Type::BT_INT); t[0].st(Type::ST_SET); rb(env, m, ASTString("deopt"), t, b_deopt_intset); } { std::vector t(2); t[0] = Type::varbot(1); t[1] = Type::parint(1); rb(env, m, ASTString("sort_by"), t, b_sort_by_int); t[0] = Type::bot(1); rb(env, m, ASTString("sort_by"), t, b_sort_by_int); t[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("sort_by"), t, b_sort_by_int); } { std::vector t(2); t[0] = Type::varbot(1); t[1] = Type::parfloat(1); rb(env, m, ASTString("sort_by"), t, b_sort_by_float); t[0] = Type::bot(1); rb(env, m, ASTString("sort_by"), t, b_sort_by_float); t[0].ot(Type::OT_OPTIONAL); rb(env, m, ASTString("sort_by"), t, b_sort_by_float); } { std::vector t(1); t[0] = Type::parint(1); rb(env, m, ASTString("sort"), t, b_sort); rb(env, m, ASTString("arg_min"), t, b_arg_min_int); rb(env, m, ASTString("arg_max"), t, b_arg_max_int); t[0] = Type::parbool(1); rb(env, m, ASTString("sort"), t, b_sort); t[0] = Type::parfloat(1); rb(env, m, ASTString("sort"), t, b_sort); rb(env, m, ASTString("arg_min"), t, b_arg_min_float); rb(env, m, ASTString("arg_max"), t, b_arg_max_float); } { std::vector t(1); t[0] = Type::parint(1); rb(env, m, ASTString("inverse"), t, b_inverse, true); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("atan"), t, b_atan); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("cos"), t, b_cos); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("sin"), t, b_sin); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("asin"), t, b_asin); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("acos"), t, b_acos); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("tan"), t, b_tan); } { std::vector t(2); t[0] = Type::parfloat(); t[1] = Type::parfloat(); rb(env, m, ASTString("normal"),t,b_normal_float_float); t[0] = Type::parint(); rb(env, m, ASTString("normal"),t,b_normal_int_float); } { std::vector t(2); t[0] = Type::parfloat(); t[1] = Type::parfloat(); rb(env, m, ASTString("uniform"),t,b_uniform_float); t[0] = Type::parint(); t[1] = Type::parint(); rb(env, m, ASTString("uniform"),t,b_uniform_int); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("poisson"),t,b_poisson_float); t[0] = Type::parint(); rb(env, m, ASTString("poisson"),t,b_poisson_int); } { std::vector t(2); t[0] = Type::parfloat(); t[1] = Type::parfloat(); rb(env, m, ASTString("gamma"),t,b_gamma_float_float); t[0] = Type::parint(); rb(env, m, ASTString("gamma"),t,b_gamma_int_float); } { std::vector t(2); t[0] = Type::parfloat(); t[1] = Type::parfloat(); rb(env, m, ASTString("weibull"),t,b_weibull_float_float); t[0] = Type::parint(); rb(env, m, ASTString("weibull"),t,b_weibull_int_float); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("exponential"),t,b_exponential_float); t[0] = Type::parint(); rb(env, m, ASTString("exponential"),t,b_exponential_int); } { std::vector t(2); t[0] = Type::parfloat(); t[1] = Type::parfloat(); rb(env, m, ASTString("lognormal"),t,b_lognormal_float_float); t[0] = Type::parint(); rb(env, m, ASTString("lognormal"),t,b_lognormal_int_float); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("chisquared"),t,b_chisquared_float); t[0] = Type::parint(); rb(env, m, ASTString("chisquared"),t,b_chisquared_int); } { std::vector t(2); t[0] = Type::parfloat(); t[1] = Type::parfloat(); rb(env, m, ASTString("cauchy"),t,b_cauchy_float_float); t[0] = Type::parint(); rb(env, m, ASTString("cauchy"),t,b_cauchy_int_float); } { std::vector t(2); t[0] = Type::parfloat(); t[1] = Type::parfloat(); rb(env, m, ASTString("fdistribution"),t,b_fdistribution_float_float); t[0] = Type::parint(); t[1] = Type::parint(); rb(env, m, ASTString("fdistribution"),t,b_fdistribution_int_int); } { std::vector t(1); t[0] = Type::parfloat(); rb(env, m, ASTString("tdistribution"),t,b_tdistribution_float); t[0] = Type::parint(); rb(env, m, ASTString("tdistribution"),t,b_tdistribution_int); } { std::vector t(1); t[0] = Type::parint(1); rb(env, m, ASTString("discrete_distribution"),t,b_discrete_distribution); } { std::vector t(1); t[0] = Type::parint(); rb(env, m, ASTString("bernoulli"),t,b_bernoulli); } { std::vector t(2); t[0] = Type::parint(); t[1] = Type::parfloat(); rb(env, m, ASTString("binomial"),t,b_binomial); } { std::vector t(2); t[0] = Type::parsetint(); t[1] = Type::parint(); rb(env, m, ASTString("to_enum"),t,b_to_enum); rb(env, m, ASTString("enum_next"),t,b_enum_next); rb(env, m, ASTString("enum_prev"),t,b_enum_prev); } { rb(env, m, ASTString("mzn_compiler_version"), std::vector(), b_mzn_compiler_version); } { std::vector t(2); t[0] = Type::varint(1); t[1] = Type::parstring(); rb(env, m, ASTString("fzn_regular"),t,b_regular_from_string,true); } } } libminizinc-2.4.2/lib/cached/000077500000000000000000000000001360574160400160115ustar00rootroot00000000000000libminizinc-2.4.2/lib/cached/lexer.yy.cpp000066400000000000000000003051701360574160400203020ustar00rootroot00000000000000 #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 6 #define YY_FLEX_SUBMINOR_VERSION 4 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif #ifdef yy_create_buffer #define mzn_yy_create_buffer_ALREADY_DEFINED #else #define yy_create_buffer mzn_yy_create_buffer #endif #ifdef yy_delete_buffer #define mzn_yy_delete_buffer_ALREADY_DEFINED #else #define yy_delete_buffer mzn_yy_delete_buffer #endif #ifdef yy_scan_buffer #define mzn_yy_scan_buffer_ALREADY_DEFINED #else #define yy_scan_buffer mzn_yy_scan_buffer #endif #ifdef yy_scan_string #define mzn_yy_scan_string_ALREADY_DEFINED #else #define yy_scan_string mzn_yy_scan_string #endif #ifdef yy_scan_bytes #define mzn_yy_scan_bytes_ALREADY_DEFINED #else #define yy_scan_bytes mzn_yy_scan_bytes #endif #ifdef yy_init_buffer #define mzn_yy_init_buffer_ALREADY_DEFINED #else #define yy_init_buffer mzn_yy_init_buffer #endif #ifdef yy_flush_buffer #define mzn_yy_flush_buffer_ALREADY_DEFINED #else #define yy_flush_buffer mzn_yy_flush_buffer #endif #ifdef yy_load_buffer_state #define mzn_yy_load_buffer_state_ALREADY_DEFINED #else #define yy_load_buffer_state mzn_yy_load_buffer_state #endif #ifdef yy_switch_to_buffer #define mzn_yy_switch_to_buffer_ALREADY_DEFINED #else #define yy_switch_to_buffer mzn_yy_switch_to_buffer #endif #ifdef yypush_buffer_state #define mzn_yypush_buffer_state_ALREADY_DEFINED #else #define yypush_buffer_state mzn_yypush_buffer_state #endif #ifdef yypop_buffer_state #define mzn_yypop_buffer_state_ALREADY_DEFINED #else #define yypop_buffer_state mzn_yypop_buffer_state #endif #ifdef yyensure_buffer_stack #define mzn_yyensure_buffer_stack_ALREADY_DEFINED #else #define yyensure_buffer_stack mzn_yyensure_buffer_stack #endif #ifdef yylex #define mzn_yylex_ALREADY_DEFINED #else #define yylex mzn_yylex #endif #ifdef yyrestart #define mzn_yyrestart_ALREADY_DEFINED #else #define yyrestart mzn_yyrestart #endif #ifdef yylex_init #define mzn_yylex_init_ALREADY_DEFINED #else #define yylex_init mzn_yylex_init #endif #ifdef yylex_init_extra #define mzn_yylex_init_extra_ALREADY_DEFINED #else #define yylex_init_extra mzn_yylex_init_extra #endif #ifdef yylex_destroy #define mzn_yylex_destroy_ALREADY_DEFINED #else #define yylex_destroy mzn_yylex_destroy #endif #ifdef yyget_debug #define mzn_yyget_debug_ALREADY_DEFINED #else #define yyget_debug mzn_yyget_debug #endif #ifdef yyset_debug #define mzn_yyset_debug_ALREADY_DEFINED #else #define yyset_debug mzn_yyset_debug #endif #ifdef yyget_extra #define mzn_yyget_extra_ALREADY_DEFINED #else #define yyget_extra mzn_yyget_extra #endif #ifdef yyset_extra #define mzn_yyset_extra_ALREADY_DEFINED #else #define yyset_extra mzn_yyset_extra #endif #ifdef yyget_in #define mzn_yyget_in_ALREADY_DEFINED #else #define yyget_in mzn_yyget_in #endif #ifdef yyset_in #define mzn_yyset_in_ALREADY_DEFINED #else #define yyset_in mzn_yyset_in #endif #ifdef yyget_out #define mzn_yyget_out_ALREADY_DEFINED #else #define yyget_out mzn_yyget_out #endif #ifdef yyset_out #define mzn_yyset_out_ALREADY_DEFINED #else #define yyset_out mzn_yyset_out #endif #ifdef yyget_leng #define mzn_yyget_leng_ALREADY_DEFINED #else #define yyget_leng mzn_yyget_leng #endif #ifdef yyget_text #define mzn_yyget_text_ALREADY_DEFINED #else #define yyget_text mzn_yyget_text #endif #ifdef yyget_lineno #define mzn_yyget_lineno_ALREADY_DEFINED #else #define yyget_lineno mzn_yyget_lineno #endif #ifdef yyset_lineno #define mzn_yyset_lineno_ALREADY_DEFINED #else #define yyset_lineno mzn_yyset_lineno #endif #ifdef yyget_column #define mzn_yyget_column_ALREADY_DEFINED #else #define yyget_column mzn_yyget_column #endif #ifdef yyset_column #define mzn_yyset_column_ALREADY_DEFINED #else #define yyset_column mzn_yyset_column #endif #ifdef yywrap #define mzn_yywrap_ALREADY_DEFINED #else #define yywrap mzn_yywrap #endif #ifdef yyget_lval #define mzn_yyget_lval_ALREADY_DEFINED #else #define yyget_lval mzn_yyget_lval #endif #ifdef yyset_lval #define mzn_yyset_lval_ALREADY_DEFINED #else #define yyset_lval mzn_yyset_lval #endif #ifdef yyget_lloc #define mzn_yyget_lloc_ALREADY_DEFINED #else #define yyget_lloc mzn_yyget_lloc #endif #ifdef yyset_lloc #define mzn_yyset_lloc_ALREADY_DEFINED #else #define yyset_lloc mzn_yyset_lloc #endif #ifdef yyalloc #define mzn_yyalloc_ALREADY_DEFINED #else #define yyalloc mzn_yyalloc #endif #ifdef yyrealloc #define mzn_yyrealloc_ALREADY_DEFINED #else #define yyrealloc mzn_yyrealloc #endif #ifdef yyfree #define mzn_yyfree_ALREADY_DEFINED #else #define yyfree mzn_yyfree #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #ifndef SIZE_MAX #define SIZE_MAX (~(size_t)0) #endif #endif /* ! C99 */ #endif /* ! FLEXINT_H */ /* begin standard C++ headers. */ /* TODO: this is always defined, so inline it */ #define yyconst const #if defined(__GNUC__) && __GNUC__ >= 3 #define yynoreturn __attribute__((__noreturn__)) #else #define yynoreturn #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an * integer in range [0..255] for use as an array index. */ #define YY_SC_TO_UI(c) ((YY_CHAR) (c)) /* An opaque pointer. */ #ifndef YY_TYPEDEF_YY_SCANNER_T #define YY_TYPEDEF_YY_SCANNER_T typedef void* yyscan_t; #endif /* For convenience, these vars (plus the bison vars far below) are macros in the reentrant scanner. */ #define yyin yyg->yyin_r #define yyout yyg->yyout_r #define yyextra yyg->yyextra_r #define yyleng yyg->yyleng_r #define yytext yyg->yytext_r #define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) #define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) #define yy_flex_debug yyg->yy_flex_debug_r /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN yyg->yy_start = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START ((yyg->yy_start - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart( yyin , yyscanner ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k. * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. * Ditto for the __ia64__ case accordingly. */ #define YY_BUF_SIZE 32768 #else #define YY_BUF_SIZE 16384 #endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) #define YY_LINENO_REWIND_TO(ptr) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = yyg->yy_hold_char; \ YY_RESTORE_YY_MORE_OFFSET \ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ int yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] void yyrestart ( FILE *input_file , yyscan_t yyscanner ); void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); void yypop_buffer_state ( yyscan_t yyscanner ); static void yyensure_buffer_stack ( yyscan_t yyscanner ); static void yy_load_buffer_state ( yyscan_t yyscanner ); static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); #define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner) YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); void *yyalloc ( yy_size_t , yyscan_t yyscanner ); void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); void yyfree ( void * , yyscan_t yyscanner ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (yyscanner); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (yyscanner); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ #define mzn_yywrap(yyscanner) (/*CONSTCOND*/1) #define YY_SKIP_YYWRAP typedef flex_uint8_t YY_CHAR; typedef int yy_state_type; #define yytext_ptr yytext_r static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); static int yy_get_next_buffer ( yyscan_t yyscanner ); static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ yyg->yytext_ptr = yy_bp; \ yyleng = (int) (yy_cp - yy_bp); \ yyg->yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; #define YY_NUM_RULES 181 #define YY_END_OF_BUFFER 182 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static const flex_int16_t yy_accept[500] = { 0, 0, 0, 168, 168, 168, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 182, 180, 3, 2, 180, 167, 180, 23, 180, 164, 103, 99, 33, 101, 33, 105, 29, 29, 33, 112, 122, 116, 142, 19, 180, 21, 107, 37, 180, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 33, 180, 180, 180, 1, 168, 178, 177, 175, 177, 1, 176, 177, 16, 18, 17, 1, 6, 8, 7, 1, 11, 13, 12, 1, 165, 166, 124, 0, 163, 23, 0, 0, 143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 126, 34, 14, 134, 0, 29, 0, 0, 0, 36, 128, 114, 111, 120, 118, 142, 20, 132, 144, 144, 0, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 56, 61, 142, 142, 142, 142, 142, 142, 72, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 22, 137, 136, 139, 138, 151, 0, 0, 0, 0, 168, 172, 171, 173, 171, 169, 170, 174, 16, 15, 6, 5, 11, 10, 162, 163, 0, 104, 100, 0, 102, 0, 0, 106, 0, 113, 0, 0, 123, 0, 117, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 30, 0, 32, 0, 27, 28, 130, 144, 144, 0, 179, 38, 40, 142, 142, 142, 142, 142, 142, 46, 142, 142, 142, 142, 142, 142, 142, 142, 63, 64, 142, 142, 142, 68, 70, 74, 142, 75, 142, 142, 142, 79, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 94, 142, 97, 152, 153, 154, 145, 146, 147, 150, 155, 156, 161, 160, 157, 158, 159, 148, 149, 162, 125, 110, 127, 35, 135, 129, 0, 115, 121, 119, 133, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 140, 9, 0, 0, 0, 0, 144, 142, 142, 42, 43, 142, 142, 48, 50, 142, 53, 142, 142, 142, 142, 142, 142, 65, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 88, 89, 24, 142, 91, 142, 142, 142, 131, 0, 47, 0, 69, 71, 0, 0, 0, 0, 98, 0, 31, 0, 0, 26, 144, 142, 41, 142, 142, 142, 52, 25, 54, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 80, 142, 142, 142, 142, 90, 92, 142, 96, 49, 0, 0, 0, 0, 0, 0, 26, 144, 142, 142, 142, 51, 142, 142, 142, 142, 142, 142, 73, 142, 77, 142, 81, 82, 142, 142, 142, 0, 0, 0, 0, 93, 144, 142, 142, 45, 142, 57, 142, 142, 142, 142, 142, 78, 142, 86, 142, 0, 83, 0, 0, 144, 142, 142, 55, 58, 142, 66, 67, 142, 84, 142, 0, 0, 87, 144, 142, 142, 59, 76, 142, 0, 85, 141, 39, 44, 142, 60, 142, 142, 142, 95, 0 } ; static const YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 2, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 6, 1, 7, 8, 1, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 19, 19, 19, 19, 19, 20, 20, 21, 14, 22, 23, 24, 1, 1, 25, 25, 25, 25, 26, 25, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 27, 27, 27, 27, 27, 27, 27, 29, 27, 27, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 27, 46, 47, 48, 49, 50, 27, 51, 52, 53, 54, 55, 56, 57, 58, 59, 14, 60, 14, 61, 1, 62, 1, 1, 63, 1, 1, 64, 65, 66, 67, 68, 1, 1, 1, 1, 1, 69, 1, 70, 1, 71, 1, 1, 1, 1, 1, 1, 1, 1, 1, 72, 1, 73, 1, 1, 1, 74, 75, 1, 76, 77, 78, 79, 1, 80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 81, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 82, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static const YY_CHAR yy_meta[84] = { 0, 1, 1, 2, 3, 1, 4, 5, 1, 1, 1, 1, 6, 1, 1, 1, 7, 1, 8, 8, 8, 1, 1, 1, 1, 9, 9, 10, 9, 10, 1, 4, 1, 1, 11, 12, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3 } ; static const flex_int16_t yy_base[521] = { 0, 0, 0, 81, 85, 89, 93, 91, 95, 97, 98, 99, 101, 850, 849, 848, 847, 857, 862, 862, 862, 833, 862, 848, 0, 180, 862, 862, 841, 862, 829, 836, 74, 99, 111, 830, 99, 827, 826, 0, 788, 830, 862, 862, 797, 0, 84, 796, 72, 94, 94, 90, 102, 101, 110, 795, 108, 116, 803, 117, 147, 794, 805, 797, 790, 806, 194, 757, 148, 862, 0, 862, 862, 862, 212, 862, 862, 220, 0, 862, 819, 0, 0, 862, 818, 0, 0, 862, 817, 0, 862, 862, 862, 0, 0, 0, 124, 138, 862, 168, 222, 214, 224, 177, 227, 216, 239, 816, 179, 235, 240, 243, 245, 247, 250, 254, 284, 862, 862, 862, 820, 862, 264, 290, 299, 306, 268, 862, 807, 862, 862, 862, 862, 0, 862, 862, 0, 793, 794, 115, 777, 778, 774, 777, 783, 124, 771, 207, 776, 772, 772, 0, 282, 766, 766, 760, 768, 776, 761, 0, 760, 759, 760, 770, 771, 755, 754, 760, 754, 227, 757, 751, 762, 747, 750, 749, 754, 746, 756, 744, 862, 862, 862, 862, 862, 862, 220, 286, 254, 269, 0, 862, 862, 862, 862, 862, 862, 862, 0, 862, 0, 862, 0, 862, 0, 0, 271, 862, 862, 328, 862, 329, 330, 862, 785, 862, 342, 341, 862, 344, 862, 345, 784, 862, 346, 347, 358, 359, 348, 360, 361, 362, 365, 780, 362, 390, 396, 399, 378, 322, 862, 0, 746, 755, 862, 740, 0, 752, 741, 746, 733, 748, 742, 0, 742, 737, 733, 727, 742, 739, 730, 731, 734, 0, 720, 728, 727, 0, 0, 0, 720, 0, 730, 719, 723, 0, 711, 721, 712, 723, 723, 708, 712, 719, 712, 717, 707, 711, 703, 0, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 0, 862, 862, 862, 862, 862, 862, 390, 862, 862, 862, 862, 402, 395, 862, 411, 413, 414, 418, 421, 423, 422, 425, 862, 862, 445, 418, 419, 459, 713, 699, 693, 0, 0, 697, 695, 0, 704, 706, 0, 706, 692, 691, 689, 694, 690, 0, 663, 659, 644, 650, 635, 630, 632, 623, 630, 600, 606, 0, 0, 0, 598, 0, 586, 597, 592, 862, 450, 862, 457, 862, 862, 458, 464, 466, 471, 862, 464, 467, 481, 472, 485, 543, 544, 0, 528, 532, 536, 0, 0, 0, 532, 536, 530, 521, 528, 527, 517, 530, 528, 525, 0, 523, 511, 511, 517, 0, 0, 509, 0, 862, 497, 498, 500, 502, 503, 498, 502, 500, 497, 506, 488, 0, 483, 490, 474, 453, 417, 398, 0, 419, 0, 392, 0, 0, 408, 400, 376, 504, 505, 514, 515, 862, 359, 351, 342, 0, 336, 0, 325, 298, 281, 273, 258, 0, 251, 0, 266, 517, 862, 516, 528, 240, 226, 224, 0, 0, 216, 0, 0, 227, 0, 206, 529, 530, 862, 180, 152, 141, 0, 0, 151, 531, 862, 0, 0, 0, 145, 862, 111, 55, 51, 0, 862, 582, 594, 606, 618, 626, 636, 648, 653, 656, 658, 668, 680, 692, 704, 708, 711, 715, 719, 724, 729, 731 } ; static const flex_int16_t yy_def[521] = { 0, 499, 1, 500, 500, 500, 500, 501, 501, 502, 502, 503, 503, 1, 1, 1, 1, 499, 499, 499, 499, 499, 499, 504, 505, 506, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 507, 499, 499, 499, 499, 508, 509, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 499, 499, 499, 499, 499, 510, 499, 499, 499, 499, 499, 499, 499, 511, 499, 499, 511, 512, 499, 499, 512, 513, 499, 499, 513, 499, 499, 499, 514, 515, 505, 506, 506, 499, 506, 506, 506, 506, 506, 506, 506, 506, 499, 506, 506, 506, 506, 506, 506, 506, 506, 506, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 507, 499, 499, 516, 516, 517, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 510, 499, 499, 499, 499, 499, 499, 499, 511, 499, 512, 499, 513, 499, 518, 515, 506, 499, 499, 506, 499, 506, 506, 499, 499, 499, 506, 506, 499, 506, 499, 506, 499, 499, 506, 506, 506, 506, 506, 506, 506, 506, 506, 499, 499, 499, 499, 499, 519, 499, 499, 516, 516, 517, 499, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 518, 499, 499, 499, 499, 499, 499, 506, 499, 499, 499, 499, 506, 506, 499, 506, 506, 506, 506, 506, 506, 506, 506, 499, 499, 499, 520, 520, 499, 516, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 499, 506, 499, 506, 499, 499, 506, 506, 506, 506, 499, 499, 499, 499, 499, 499, 516, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 499, 506, 506, 506, 506, 506, 499, 499, 516, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 506, 506, 506, 506, 499, 516, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 506, 499, 506, 506, 516, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 506, 506, 499, 516, 507, 507, 507, 507, 507, 506, 499, 516, 507, 507, 507, 499, 507, 507, 507, 507, 0, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499 } ; static const flex_int16_t yy_nxt[946] = { 0, 18, 19, 20, 19, 21, 22, 23, 24, 25, 26, 18, 27, 28, 29, 30, 31, 32, 33, 34, 34, 35, 36, 37, 38, 39, 39, 39, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 39, 39, 52, 39, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 39, 39, 65, 66, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 67, 68, 69, 71, 72, 120, 73, 71, 72, 498, 73, 71, 72, 79, 76, 71, 72, 79, 76, 83, 83, 87, 80, 87, 121, 497, 80, 142, 84, 84, 88, 74, 88, 128, 122, 74, 123, 123, 123, 77, 143, 129, 130, 77, 124, 148, 122, 125, 123, 123, 123, 139, 98, 144, 140, 149, 124, 145, 124, 146, 153, 147, 151, 150, 154, 155, 98, 126, 159, 152, 124, 162, 165, 156, 499, 125, 166, 160, 157, 496, 206, 161, 245, 75, 252, 167, 163, 75, 499, 168, 169, 75, 246, 81, 170, 75, 207, 81, 253, 85, 85, 89, 495, 89, 97, 213, 171, 223, 98, 172, 493, 99, 100, 492, 101, 102, 103, 173, 499, 491, 174, 104, 105, 106, 175, 181, 182, 214, 183, 499, 107, 186, 108, 187, 188, 189, 184, 191, 109, 490, 192, 193, 210, 110, 218, 191, 111, 112, 192, 197, 208, 113, 98, 114, 209, 215, 115, 211, 219, 212, 116, 216, 194, 98, 499, 255, 499, 220, 98, 217, 194, 98, 499, 98, 499, 98, 487, 499, 98, 195, 256, 221, 98, 278, 196, 499, 486, 195, 485, 499, 499, 484, 196, 499, 483, 499, 279, 499, 224, 307, 499, 234, 234, 234, 499, 239, 239, 225, 290, 291, 292, 226, 98, 227, 482, 232, 232, 230, 232, 478, 228, 499, 231, 477, 229, 122, 232, 123, 123, 123, 476, 235, 475, 235, 499, 124, 236, 236, 236, 260, 474, 237, 261, 238, 238, 238, 301, 302, 303, 124, 238, 238, 304, 305, 262, 473, 308, 309, 310, 239, 239, 238, 238, 238, 238, 238, 238, 293, 294, 314, 312, 295, 315, 316, 98, 320, 98, 296, 499, 499, 499, 297, 298, 299, 300, 313, 98, 98, 98, 98, 98, 499, 499, 329, 499, 499, 499, 499, 499, 234, 234, 234, 472, 471, 324, 470, 318, 331, 499, 499, 499, 499, 499, 333, 469, 499, 322, 325, 372, 321, 319, 331, 468, 374, 327, 334, 326, 236, 236, 236, 98, 323, 328, 236, 236, 236, 332, 332, 332, 98, 499, 376, 377, 332, 332, 499, 98, 334, 463, 98, 98, 98, 499, 382, 332, 332, 332, 332, 332, 332, 462, 499, 373, 499, 499, 385, 385, 461, 499, 460, 375, 499, 499, 499, 459, 499, 458, 383, 416, 383, 379, 380, 384, 384, 384, 98, 98, 385, 385, 378, 381, 386, 98, 386, 98, 457, 387, 387, 387, 98, 499, 384, 384, 384, 384, 384, 384, 499, 499, 387, 387, 387, 456, 422, 499, 422, 499, 418, 423, 423, 423, 499, 387, 387, 387, 98, 98, 417, 98, 420, 98, 448, 98, 465, 419, 423, 423, 423, 421, 423, 423, 423, 98, 98, 98, 98, 455, 499, 499, 454, 499, 453, 499, 499, 499, 499, 481, 98, 489, 494, 452, 451, 447, 464, 499, 499, 499, 499, 444, 450, 445, 446, 449, 466, 479, 467, 443, 442, 499, 499, 499, 499, 441, 440, 439, 438, 437, 436, 480, 435, 434, 433, 432, 431, 430, 429, 428, 427, 426, 425, 424, 488, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 94, 415, 414, 413, 94, 94, 95, 412, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 96, 411, 410, 96, 96, 96, 96, 96, 96, 96, 96, 96, 133, 133, 133, 133, 136, 136, 138, 138, 190, 409, 408, 407, 190, 190, 190, 190, 190, 190, 190, 190, 198, 406, 198, 198, 198, 405, 198, 198, 198, 198, 198, 198, 200, 404, 200, 200, 200, 403, 200, 200, 200, 200, 200, 200, 202, 402, 202, 202, 202, 401, 202, 202, 202, 202, 202, 202, 204, 204, 205, 205, 205, 205, 241, 241, 241, 241, 243, 243, 243, 243, 243, 306, 306, 306, 306, 238, 238, 238, 332, 332, 400, 399, 398, 397, 396, 395, 394, 393, 392, 391, 390, 389, 388, 371, 370, 369, 368, 367, 366, 365, 364, 363, 362, 361, 360, 359, 358, 357, 356, 355, 354, 353, 352, 351, 350, 349, 348, 347, 346, 345, 344, 343, 342, 341, 340, 339, 338, 337, 336, 244, 335, 330, 317, 311, 289, 288, 287, 286, 285, 284, 283, 282, 281, 280, 277, 276, 275, 274, 273, 272, 271, 270, 269, 268, 267, 266, 265, 264, 263, 259, 258, 257, 254, 251, 250, 249, 248, 247, 244, 242, 240, 233, 222, 203, 201, 199, 185, 180, 179, 178, 177, 176, 164, 158, 141, 137, 135, 134, 132, 131, 127, 119, 118, 117, 93, 92, 499, 91, 91, 90, 90, 17, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499 } ; static const flex_int16_t yy_chk[946] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 32, 3, 4, 4, 497, 4, 5, 5, 7, 5, 6, 6, 8, 6, 9, 10, 11, 7, 12, 32, 496, 8, 48, 9, 10, 11, 3, 12, 36, 33, 4, 33, 33, 33, 5, 48, 36, 36, 6, 33, 51, 34, 33, 34, 34, 34, 46, 96, 49, 46, 51, 34, 49, 33, 50, 53, 50, 52, 51, 53, 54, 97, 33, 56, 52, 34, 57, 59, 54, 96, 33, 59, 56, 54, 495, 97, 56, 139, 3, 145, 59, 57, 4, 97, 59, 59, 5, 139, 7, 59, 6, 99, 8, 145, 9, 10, 11, 493, 12, 25, 103, 60, 108, 25, 60, 487, 25, 25, 484, 25, 25, 25, 60, 99, 483, 60, 25, 25, 25, 60, 66, 66, 103, 66, 108, 25, 68, 25, 68, 68, 68, 66, 74, 25, 482, 74, 74, 101, 25, 105, 77, 25, 25, 77, 77, 100, 25, 102, 25, 100, 104, 25, 101, 105, 102, 25, 104, 74, 109, 101, 147, 105, 106, 110, 104, 77, 111, 100, 112, 102, 113, 478, 104, 114, 74, 147, 106, 115, 169, 74, 109, 476, 77, 473, 106, 110, 470, 77, 111, 469, 112, 169, 113, 109, 206, 114, 122, 122, 122, 115, 126, 126, 110, 186, 186, 186, 111, 116, 112, 468, 116, 116, 114, 116, 463, 113, 206, 115, 461, 113, 123, 116, 123, 123, 123, 459, 124, 458, 124, 116, 123, 124, 124, 124, 152, 457, 125, 152, 125, 125, 125, 188, 188, 188, 123, 125, 125, 189, 189, 152, 456, 209, 211, 212, 239, 239, 125, 125, 125, 125, 125, 125, 187, 187, 217, 216, 187, 219, 221, 224, 225, 228, 187, 209, 211, 212, 187, 187, 187, 187, 216, 226, 227, 229, 230, 231, 217, 216, 232, 219, 221, 224, 225, 228, 234, 234, 234, 455, 453, 228, 451, 224, 234, 226, 227, 229, 230, 231, 238, 450, 232, 226, 228, 313, 225, 224, 234, 449, 319, 230, 238, 229, 235, 235, 235, 318, 227, 231, 236, 236, 236, 237, 237, 237, 321, 313, 322, 323, 237, 237, 319, 324, 238, 443, 325, 327, 326, 318, 328, 237, 237, 237, 237, 237, 237, 442, 321, 318, 322, 323, 332, 333, 441, 324, 438, 321, 325, 327, 326, 436, 328, 434, 331, 373, 331, 325, 326, 331, 331, 331, 375, 378, 332, 333, 324, 327, 334, 379, 334, 380, 433, 334, 334, 334, 381, 373, 383, 383, 383, 384, 384, 384, 375, 378, 386, 386, 386, 432, 385, 379, 385, 380, 378, 385, 385, 385, 381, 387, 387, 387, 417, 418, 375, 419, 380, 420, 421, 444, 445, 379, 422, 422, 422, 381, 423, 423, 423, 446, 447, 466, 464, 431, 417, 418, 430, 419, 429, 420, 421, 444, 445, 467, 479, 480, 488, 427, 426, 420, 444, 446, 447, 466, 464, 417, 425, 418, 419, 424, 446, 464, 447, 414, 411, 467, 479, 480, 488, 410, 409, 408, 406, 405, 404, 466, 403, 402, 401, 400, 399, 398, 397, 393, 392, 391, 389, 388, 479, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 501, 501, 501, 501, 501, 501, 501, 501, 501, 501, 501, 501, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 503, 504, 371, 370, 369, 504, 504, 505, 367, 505, 505, 505, 505, 505, 505, 505, 505, 505, 505, 506, 363, 362, 506, 506, 506, 506, 506, 506, 506, 506, 506, 507, 507, 507, 507, 508, 508, 509, 509, 510, 361, 360, 359, 510, 510, 510, 510, 510, 510, 510, 510, 511, 358, 511, 511, 511, 357, 511, 511, 511, 511, 511, 511, 512, 356, 512, 512, 512, 355, 512, 512, 512, 512, 512, 512, 513, 354, 513, 513, 513, 353, 513, 513, 513, 513, 513, 513, 514, 514, 515, 515, 515, 515, 516, 516, 516, 516, 517, 517, 517, 517, 517, 518, 518, 518, 518, 519, 519, 519, 520, 520, 351, 350, 349, 348, 347, 346, 344, 343, 341, 340, 337, 336, 335, 288, 287, 286, 285, 284, 283, 282, 281, 280, 279, 278, 277, 276, 274, 273, 272, 270, 266, 265, 264, 262, 261, 260, 259, 258, 257, 256, 255, 254, 252, 251, 250, 249, 248, 247, 245, 243, 242, 233, 222, 214, 179, 178, 177, 176, 175, 174, 173, 172, 171, 170, 168, 167, 166, 165, 164, 163, 162, 161, 160, 158, 157, 156, 155, 154, 153, 150, 149, 148, 146, 144, 143, 142, 141, 140, 138, 137, 128, 120, 107, 88, 84, 80, 67, 65, 64, 63, 62, 61, 58, 55, 47, 44, 41, 40, 38, 37, 35, 31, 30, 28, 23, 21, 17, 16, 15, 14, 13, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499 } ; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #if defined __GNUC__ #pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wsign-compare" #pragma GCC diagnostic ignored "-Wdeprecated" #elif defined _MSC_VER #pragma warning(push, 1) #endif namespace MiniZinc{ class ParserLocation; } #define YYLTYPE MiniZinc::ParserLocation #define YYLTYPE_IS_DECLARED 1 #define YYLTYPE_IS_TRIVIAL 0 #include namespace MiniZinc { int utf8len(const char* s) { int l=0; for (int i=0; s[i] != '\0'; i++) if ((s[i] & 0xc0) != 0x80) l++; return l; } int yy_input_proc(char* buf, int size, yyscan_t yyscanner); } #define YY_INPUT(buf, result, max_size) \ result = ::MiniZinc::yy_input_proc(buf, max_size, yyscanner); #define YY_USER_ACTION \ { MiniZinc::ParserState* parm = \ static_cast(yyget_extra(yyscanner)); \ yylloc->first_line(yylloc->last_line()); \ yylloc->first_column(yylloc->last_column()+1); \ if(parm->hadNewline) { \ parm->hadNewline=false; \ parm->lineStartPos += parm->nTokenNextStart; \ parm->nTokenNextStart=1; \ yylloc->last_line(yylloc->last_line()+1); \ yylloc->first_line(yylloc->last_line()); \ yylloc->first_column(1); \ } \ if(yytext[0] == '\n') { \ parm->hadNewline=true; \ parm->nTokenNextStart+=0; \ } else { \ parm->nTokenNextStart+=yyleng; \ } \ yylloc->last_column(yylloc->first_column()+::MiniZinc::utf8len(yytext)-1); \ } namespace MiniZinc { bool hexstrtointval(const char* s, long long int& v) { std::istringstream iss(s); iss >> std::hex >> v; return !iss.fail(); } bool octstrtointval(const char* s, long long int& v) { std::istringstream iss(s); iss >> std::oct >> v; return !iss.fail(); } bool fast_strtointval(const char* s, long long int& v) { MiniZinc::IntVal x = 0; try { for (; *s != '\0'; ++s) { x = (x*10) + (*s - '0'); } } catch (MiniZinc::ArithmeticError&) { return false; } v = x.toInt(); return true; } bool strtofloatval(const char* s, double& v) { std::istringstream iss(s); iss >> v; return !iss.fail(); } void clearBuffer(void* parm) { MiniZinc::ParserState* pp = static_cast(parm); pp->stringBuffer = ""; } void appendBufferString(void* parm, const char* s) { MiniZinc::ParserState* pp = static_cast(parm); pp->stringBuffer += s; } void appendBufferChar(void* parm, char s) { MiniZinc::ParserState* pp = static_cast(parm); pp->stringBuffer += s; } char* bufferData(void* parm) { MiniZinc::ParserState* pp = static_cast(parm); return strdup(pp->stringBuffer.c_str()); } } #define INITIAL 0 #define string 1 #define string_quote 2 #define multilinecomment 3 #define doccomment 4 #define doccomment_file 5 #define bracket_exp 6 #define quoted_exp 7 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif /* Holds the entire state of the reentrant scanner. */ struct yyguts_t { /* User-defined. Not touched by flex. */ YY_EXTRA_TYPE yyextra_r; /* The rest are the same as the globals declared in the non-reentrant scanner. */ FILE *yyin_r, *yyout_r; size_t yy_buffer_stack_top; /**< index of top of stack. */ size_t yy_buffer_stack_max; /**< capacity of stack. */ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ char yy_hold_char; int yy_n_chars; int yyleng_r; char *yy_c_buf_p; int yy_init; int yy_start; int yy_did_buffer_switch_on_eof; int yy_start_stack_ptr; int yy_start_stack_depth; int *yy_start_stack; yy_state_type yy_last_accepting_state; char* yy_last_accepting_cpos; int yylineno_r; int yy_flex_debug_r; char *yytext_r; int yy_more_flag; int yy_more_len; YYSTYPE * yylval_r; YYLTYPE * yylloc_r; }; /* end struct yyguts_t */ static int yy_init_globals ( yyscan_t yyscanner ); /* This must go here because YYSTYPE and YYLTYPE are included * from bison output in section 1.*/ # define yylval yyg->yylval_r # define yylloc yyg->yylloc_r int yylex_init (yyscan_t* scanner); int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy ( yyscan_t yyscanner ); int yyget_debug ( yyscan_t yyscanner ); void yyset_debug ( int debug_flag , yyscan_t yyscanner ); YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); FILE *yyget_in ( yyscan_t yyscanner ); void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); FILE *yyget_out ( yyscan_t yyscanner ); void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); int yyget_leng ( yyscan_t yyscanner ); char *yyget_text ( yyscan_t yyscanner ); int yyget_lineno ( yyscan_t yyscanner ); void yyset_lineno ( int _line_number , yyscan_t yyscanner ); int yyget_column ( yyscan_t yyscanner ); void yyset_column ( int _column_no , yyscan_t yyscanner ); YYSTYPE * yyget_lval ( yyscan_t yyscanner ); void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner ); YYLTYPE *yyget_lloc ( yyscan_t yyscanner ); void yyset_lloc ( YYLTYPE * yylloc_param , yyscan_t yyscanner ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap ( yyscan_t yyscanner ); #else extern int yywrap ( yyscan_t yyscanner ); #endif #endif #ifndef YY_NO_UNPUT static void yyunput ( int c, char *buf_ptr , yyscan_t yyscanner); #endif #ifndef yytext_ptr static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen ( const char * , yyscan_t yyscanner); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput ( yyscan_t yyscanner ); #else static int input ( yyscan_t yyscanner ); #endif #endif static void yy_push_state ( int _new_state , yyscan_t yyscanner); static void yy_pop_state ( yyscan_t yyscanner ); static int yy_top_state ( yyscan_t yyscanner ); /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k */ #define YY_READ_BUF_SIZE 16384 #else #define YY_READ_BUF_SIZE 8192 #endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ int n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex \ (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner); #define YY_DECL int yylex \ (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK /*LINTED*/break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { yy_state_type yy_current_state; char *yy_cp, *yy_bp; int yy_act; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yylval = yylval_param; yylloc = yylloc_param; if ( !yyg->yy_init ) { yyg->yy_init = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! yyg->yy_start ) yyg->yy_start = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (yyscanner); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); } yy_load_buffer_state( yyscanner ); } { while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { yy_cp = yyg->yy_c_buf_p; /* Support of yytext. */ *yy_cp = yyg->yy_hold_char; /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = yyg->yy_start; yy_match: do { YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 500 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 862 ); yy_find_action: yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = yyg->yy_hold_char; yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; goto yy_find_action; case 1: YY_RULE_SETUP { return MZN_INVALID_NULL; } YY_BREAK case 2: /* rule 2 can match eol */ YY_RULE_SETUP { } YY_BREAK case 3: YY_RULE_SETUP { /* ignore whitespace */ } YY_BREAK case 4: YY_RULE_SETUP { yy_push_state(doccomment,yyscanner); ::MiniZinc::clearBuffer(yyget_extra(yyscanner)); } YY_BREAK case 5: YY_RULE_SETUP { yylval->sValue = ::MiniZinc::bufferData(yyget_extra(yyscanner)); yy_pop_state(yyscanner); return MZN_DOC_COMMENT; } YY_BREAK case 6: YY_RULE_SETUP { ::MiniZinc::appendBufferString(yyget_extra(yyscanner), yytext); } YY_BREAK case 7: YY_RULE_SETUP { ::MiniZinc::appendBufferString(yyget_extra(yyscanner), yytext); } YY_BREAK case 8: /* rule 8 can match eol */ YY_RULE_SETUP { ::MiniZinc::appendBufferString(yyget_extra(yyscanner), yytext); } YY_BREAK case 9: YY_RULE_SETUP { yy_push_state(doccomment_file,yyscanner); ::MiniZinc::clearBuffer(yyget_extra(yyscanner)); } YY_BREAK case 10: YY_RULE_SETUP { yylval->sValue = ::MiniZinc::bufferData(yyget_extra(yyscanner)); yy_pop_state(yyscanner); return MZN_DOC_FILE_COMMENT; } YY_BREAK case 11: YY_RULE_SETUP { ::MiniZinc::appendBufferString(yyget_extra(yyscanner), yytext); } YY_BREAK case 12: YY_RULE_SETUP { ::MiniZinc::appendBufferString(yyget_extra(yyscanner), yytext); } YY_BREAK case 13: /* rule 13 can match eol */ YY_RULE_SETUP { ::MiniZinc::appendBufferString(yyget_extra(yyscanner), yytext); } YY_BREAK case 14: YY_RULE_SETUP { yy_push_state(multilinecomment,yyscanner); } YY_BREAK case 15: YY_RULE_SETUP { yy_pop_state(yyscanner); } YY_BREAK case 16: YY_RULE_SETUP { } YY_BREAK case 17: YY_RULE_SETUP { } YY_BREAK case 18: /* rule 18 can match eol */ YY_RULE_SETUP { } YY_BREAK case 19: YY_RULE_SETUP { return MZN_LEFT_BRACKET; } YY_BREAK case 20: YY_RULE_SETUP { return MZN_LEFT_2D_BRACKET; } YY_BREAK case 21: YY_RULE_SETUP { return MZN_RIGHT_BRACKET; } YY_BREAK case 22: YY_RULE_SETUP { return MZN_RIGHT_2D_BRACKET; } YY_BREAK case 23: YY_RULE_SETUP { /* ignore comments */ } YY_BREAK case 24: YY_RULE_SETUP { yylval->iValue = 1; return MZN_BOOL_LITERAL; } YY_BREAK case 25: YY_RULE_SETUP { yylval->iValue = 0; return MZN_BOOL_LITERAL; } YY_BREAK case 26: YY_RULE_SETUP { if (::MiniZinc::strtofloatval(yytext, yylval->dValue)) return MZN_FLOAT_LITERAL; else return MZN_INVALID_FLOAT_LITERAL; } YY_BREAK case 27: YY_RULE_SETUP { if (::MiniZinc::hexstrtointval(yytext+2, yylval->iValue)) return MZN_INTEGER_LITERAL; else return MZN_INVALID_INTEGER_LITERAL; } YY_BREAK case 28: YY_RULE_SETUP { if (::MiniZinc::octstrtointval(yytext+2, yylval->iValue)) return MZN_INTEGER_LITERAL; else return MZN_INVALID_INTEGER_LITERAL; } YY_BREAK case 29: YY_RULE_SETUP { if (::MiniZinc::fast_strtointval(yytext, yylval->iValue)) return MZN_INTEGER_LITERAL; else return MZN_INVALID_INTEGER_LITERAL; } YY_BREAK case 30: YY_RULE_SETUP { if (::MiniZinc::strtofloatval(yytext, yylval->dValue)) return MZN_FLOAT_LITERAL; else return MZN_INVALID_FLOAT_LITERAL; } YY_BREAK case 31: YY_RULE_SETUP { if (::MiniZinc::strtofloatval(yytext, yylval->dValue)) return MZN_FLOAT_LITERAL; else return MZN_INVALID_FLOAT_LITERAL; } YY_BREAK case 32: YY_RULE_SETUP { if (::MiniZinc::strtofloatval(yytext, yylval->dValue)) return MZN_FLOAT_LITERAL; else return MZN_INVALID_FLOAT_LITERAL; } YY_BREAK case 33: YY_RULE_SETUP { return *yytext; } YY_BREAK case 34: YY_RULE_SETUP { return MZN_DOTDOT; } YY_BREAK case 35: YY_RULE_SETUP { return MZN_DOTDOT_QUOTED; } YY_BREAK case 36: YY_RULE_SETUP { return MZN_COLONCOLON; } YY_BREAK case 37: YY_RULE_SETUP { return MZN_UNDERSCORE; } YY_BREAK case 38: YY_RULE_SETUP { return MZN_ANN; } YY_BREAK case 39: YY_RULE_SETUP { return MZN_ANNOTATION; } YY_BREAK case 40: YY_RULE_SETUP { return MZN_ANY; } YY_BREAK case 41: YY_RULE_SETUP { return MZN_ARRAY; } YY_BREAK case 42: YY_RULE_SETUP { return MZN_BOOL; } YY_BREAK case 43: YY_RULE_SETUP { return MZN_CASE; } YY_BREAK case 44: YY_RULE_SETUP { return MZN_CONSTRAINT; } YY_BREAK case 45: YY_RULE_SETUP { return MZN_DEFAULT; } YY_BREAK case 46: YY_RULE_SETUP { return MZN_IDIV; } YY_BREAK case 47: YY_RULE_SETUP { return MZN_IDIV_QUOTED; } YY_BREAK case 48: YY_RULE_SETUP { return MZN_DIFF; } YY_BREAK case 49: YY_RULE_SETUP { return MZN_DIFF_QUOTED; } YY_BREAK case 50: YY_RULE_SETUP { return MZN_ELSE; } YY_BREAK case 51: YY_RULE_SETUP { return MZN_ELSEIF; } YY_BREAK case 52: YY_RULE_SETUP { return MZN_ENDIF; } YY_BREAK case 53: YY_RULE_SETUP { return MZN_ENUM; } YY_BREAK case 54: YY_RULE_SETUP { return MZN_FLOAT; } YY_BREAK case 55: YY_RULE_SETUP { return MZN_FUNCTION; } YY_BREAK case 56: YY_RULE_SETUP { return MZN_IF; } YY_BREAK case 57: YY_RULE_SETUP { return MZN_INCLUDE; } YY_BREAK case 58: YY_RULE_SETUP { return MZN_INFINITY; } YY_BREAK case 59: YY_RULE_SETUP { return MZN_INTERSECT; } YY_BREAK case 60: YY_RULE_SETUP { return MZN_INTERSECT_QUOTED; } YY_BREAK case 61: YY_RULE_SETUP { return MZN_IN; } YY_BREAK case 62: YY_RULE_SETUP { return MZN_IN_QUOTED; } YY_BREAK case 63: YY_RULE_SETUP { return MZN_INT; } YY_BREAK case 64: YY_RULE_SETUP { return MZN_LET; } YY_BREAK case 65: YY_RULE_SETUP { return MZN_LIST; } YY_BREAK case 66: YY_RULE_SETUP { yylval->bValue = false; return MZN_MAXIMIZE; } YY_BREAK case 67: YY_RULE_SETUP { yylval->bValue = true; return MZN_MINIMIZE; } YY_BREAK case 68: YY_RULE_SETUP { return MZN_MOD; } YY_BREAK case 69: YY_RULE_SETUP { return MZN_MOD_QUOTED; } YY_BREAK case 70: YY_RULE_SETUP { return MZN_NOT; } YY_BREAK case 71: YY_RULE_SETUP { return MZN_NOT_QUOTED; } YY_BREAK case 72: YY_RULE_SETUP { return MZN_OF; } YY_BREAK case 73: YY_RULE_SETUP { return MZN_OUTPUT; } YY_BREAK case 74: YY_RULE_SETUP { return MZN_OPT; } YY_BREAK case 75: YY_RULE_SETUP { return MZN_PAR; } YY_BREAK case 76: YY_RULE_SETUP { return MZN_PREDICATE; } YY_BREAK case 77: YY_RULE_SETUP { return MZN_RECORD; } YY_BREAK case 78: YY_RULE_SETUP { return MZN_SATISFY; } YY_BREAK case 79: YY_RULE_SETUP { return MZN_SET; } YY_BREAK case 80: YY_RULE_SETUP { return MZN_SOLVE; } YY_BREAK case 81: YY_RULE_SETUP { return MZN_STRING; } YY_BREAK case 82: YY_RULE_SETUP { return MZN_SUBSET; } YY_BREAK case 83: YY_RULE_SETUP { return MZN_SUBSET_QUOTED; } YY_BREAK case 84: YY_RULE_SETUP { return MZN_SUPERSET; } YY_BREAK case 85: YY_RULE_SETUP { return MZN_SUPERSET_QUOTED; } YY_BREAK case 86: YY_RULE_SETUP { return MZN_SYMDIFF; } YY_BREAK case 87: YY_RULE_SETUP { return MZN_SYMDIFF_QUOTED; } YY_BREAK case 88: YY_RULE_SETUP { return MZN_TEST; } YY_BREAK case 89: YY_RULE_SETUP { return MZN_THEN; } YY_BREAK case 90: YY_RULE_SETUP { return MZN_TUPLE; } YY_BREAK case 91: YY_RULE_SETUP { return MZN_TYPE; } YY_BREAK case 92: YY_RULE_SETUP { return MZN_UNION; } YY_BREAK case 93: YY_RULE_SETUP { return MZN_UNION_QUOTED; } YY_BREAK case 94: YY_RULE_SETUP { return MZN_VAR; } YY_BREAK case 95: YY_RULE_SETUP { return MZN_VARIANT_RECORD; } YY_BREAK case 96: YY_RULE_SETUP { return MZN_WHERE; } YY_BREAK case 97: YY_RULE_SETUP { return MZN_XOR; } YY_BREAK case 98: YY_RULE_SETUP { return MZN_XOR_QUOTED; } YY_BREAK case 99: YY_RULE_SETUP { return MZN_PLUS; } YY_BREAK case 100: YY_RULE_SETUP { return MZN_PLUS_QUOTED; } YY_BREAK case 101: YY_RULE_SETUP { return MZN_MINUS; } YY_BREAK case 102: YY_RULE_SETUP { return MZN_MINUS_QUOTED; } YY_BREAK case 103: YY_RULE_SETUP { return MZN_MULT; } YY_BREAK case 104: YY_RULE_SETUP { return MZN_MULT_QUOTED; } YY_BREAK case 105: YY_RULE_SETUP { return MZN_DIV; } YY_BREAK case 106: YY_RULE_SETUP { return MZN_DIV_QUOTED; } YY_BREAK case 107: YY_RULE_SETUP { return MZN_POW; } YY_BREAK case 108: YY_RULE_SETUP { return MZN_POW_QUOTED; } YY_BREAK case 109: YY_RULE_SETUP { return MZN_PLUSPLUS; } YY_BREAK case 110: YY_RULE_SETUP { return MZN_PLUSPLUS_QUOTED; } YY_BREAK case 111: YY_RULE_SETUP { return MZN_ABSENT; } YY_BREAK case 112: YY_RULE_SETUP { return MZN_LE; } YY_BREAK case 113: YY_RULE_SETUP { return MZN_LE_QUOTED; } YY_BREAK case 114: YY_RULE_SETUP { return MZN_LQ; } YY_BREAK case 115: YY_RULE_SETUP { return MZN_LQ_QUOTED; } YY_BREAK case 116: YY_RULE_SETUP { return MZN_GR; } YY_BREAK case 117: YY_RULE_SETUP { return MZN_GR_QUOTED; } YY_BREAK case 118: YY_RULE_SETUP { return MZN_GQ; } YY_BREAK case 119: YY_RULE_SETUP { return MZN_GQ_QUOTED; } YY_BREAK case 120: YY_RULE_SETUP { return MZN_EQ; } YY_BREAK case 121: YY_RULE_SETUP { return MZN_EQ_QUOTED; } YY_BREAK case 122: YY_RULE_SETUP { return MZN_EQ; } YY_BREAK case 123: YY_RULE_SETUP { return MZN_EQ_QUOTED; } YY_BREAK case 124: YY_RULE_SETUP { return MZN_NQ; } YY_BREAK case 125: YY_RULE_SETUP { return MZN_NQ_QUOTED; } YY_BREAK case 126: YY_RULE_SETUP { return MZN_IMPL; } YY_BREAK case 127: YY_RULE_SETUP { return MZN_IMPL_QUOTED; } YY_BREAK case 128: YY_RULE_SETUP { return MZN_RIMPL; } YY_BREAK case 129: YY_RULE_SETUP { return MZN_RIMPL_QUOTED; } YY_BREAK case 130: YY_RULE_SETUP { return MZN_EQUIV; } YY_BREAK case 131: YY_RULE_SETUP { return MZN_EQUIV_QUOTED; } YY_BREAK case 132: YY_RULE_SETUP { return MZN_OR; } YY_BREAK case 133: YY_RULE_SETUP { return MZN_OR_QUOTED; } YY_BREAK case 134: YY_RULE_SETUP { return MZN_AND; } YY_BREAK case 135: YY_RULE_SETUP { return MZN_AND_QUOTED; } YY_BREAK case 136: YY_RULE_SETUP { return MZN_WEAK_PLUS; } YY_BREAK case 137: YY_RULE_SETUP { return MZN_WEAK_MULT; } YY_BREAK case 138: YY_RULE_SETUP { return MZN_WEAK_EQ; } YY_BREAK case 139: YY_RULE_SETUP { return MZN_WEAK_MINUS; } YY_BREAK case 140: YY_RULE_SETUP { yylval->sValue = strdup(yytext+1); yylval->sValue[strlen(yytext)-2] = 0; return MZN_IDENTIFIER; } YY_BREAK case 141: YY_RULE_SETUP { yylval->sValue = strdup(yytext); return MZN_IDENTIFIER; } YY_BREAK case 142: YY_RULE_SETUP { yylval->sValue = strdup(yytext); return MZN_IDENTIFIER; } YY_BREAK case 143: YY_RULE_SETUP { yylval->sValue = strdup(yytext); return MZN_IDENTIFIER; } YY_BREAK case 144: YY_RULE_SETUP { MiniZinc::ParserState* parm = static_cast(yyget_extra(yyscanner)); if (parm->isFlatZinc) { yylval->sValue = strdup(yytext); return MZN_IDENTIFIER; } else { return FLATZINC_IDENTIFIER; } } YY_BREAK case 145: YY_RULE_SETUP { yylval->sValue = strdup("forall"); return MZN_IDENTIFIER; } YY_BREAK case 146: YY_RULE_SETUP { yylval->sValue = strdup("exists"); return MZN_IDENTIFIER; } YY_BREAK case 147: YY_RULE_SETUP { return MZN_IN; } YY_BREAK case 148: YY_RULE_SETUP { return MZN_SUBSET; } YY_BREAK case 149: YY_RULE_SETUP { return MZN_SUPERSET; } YY_BREAK case 150: YY_RULE_SETUP { return MZN_INFINITY; } YY_BREAK case 151: YY_RULE_SETUP { return MZN_NOT; } YY_BREAK case 152: YY_RULE_SETUP { return MZN_RIMPL; } YY_BREAK case 153: YY_RULE_SETUP { return MZN_IMPL; } YY_BREAK case 154: YY_RULE_SETUP { return MZN_EQUIV; } YY_BREAK case 155: YY_RULE_SETUP { return MZN_AND; } YY_BREAK case 156: YY_RULE_SETUP { return MZN_OR; } YY_BREAK case 157: YY_RULE_SETUP { return MZN_NQ; } YY_BREAK case 158: YY_RULE_SETUP { return MZN_LQ; } YY_BREAK case 159: YY_RULE_SETUP { return MZN_GQ; } YY_BREAK case 160: YY_RULE_SETUP { return MZN_UNION; } YY_BREAK case 161: YY_RULE_SETUP { return MZN_INTERSECT; } YY_BREAK case 162: YY_RULE_SETUP { yylval->sValue = strdup(yytext+1); return MZN_TI_ENUM_IDENTIFIER; } YY_BREAK case 163: YY_RULE_SETUP { yylval->sValue = strdup(yytext+1); return MZN_TI_IDENTIFIER; } YY_BREAK case 164: YY_RULE_SETUP { yy_push_state(bracket_exp,yyscanner); return *yytext; } YY_BREAK case 165: YY_RULE_SETUP { yy_pop_state(yyscanner); return *yytext; } YY_BREAK case 166: YY_RULE_SETUP { yy_pop_state(yyscanner); yy_pop_state(yyscanner); yy_push_state(string_quote,yyscanner); ::MiniZinc::clearBuffer(yyget_extra(yyscanner)); } YY_BREAK case 167: YY_RULE_SETUP { yy_push_state(string,yyscanner); ::MiniZinc::clearBuffer(yyget_extra(yyscanner)); } YY_BREAK case 168: YY_RULE_SETUP { ::MiniZinc::appendBufferString(yyget_extra(yyscanner), yytext); } YY_BREAK case 169: YY_RULE_SETUP { ::MiniZinc::appendBufferChar(yyget_extra(yyscanner), '\n'); } YY_BREAK case 170: YY_RULE_SETUP { ::MiniZinc::appendBufferChar(yyget_extra(yyscanner), '\t'); } YY_BREAK case 171: YY_RULE_SETUP { ::MiniZinc::appendBufferChar(yyget_extra(yyscanner), yytext[1]); } YY_BREAK case 172: YY_RULE_SETUP { ::MiniZinc::appendBufferChar(yyget_extra(yyscanner), yytext[1]); } YY_BREAK case 173: YY_RULE_SETUP { yylval->sValue = ::MiniZinc::bufferData(yyget_extra(yyscanner)); yy_push_state(quoted_exp,yyscanner); return MZN_STRING_QUOTE_START; } YY_BREAK case 174: YY_RULE_SETUP { yylval->sValue = ::MiniZinc::bufferData(yyget_extra(yyscanner)); yy_push_state(quoted_exp,yyscanner); return MZN_STRING_QUOTE_MID; } YY_BREAK case 175: YY_RULE_SETUP { yylval->sValue = ::MiniZinc::bufferData(yyget_extra(yyscanner)); yy_pop_state(yyscanner); return MZN_STRING_LITERAL; } YY_BREAK case 176: YY_RULE_SETUP { yylval->sValue = ::MiniZinc::bufferData(yyget_extra(yyscanner)); yy_pop_state(yyscanner); return MZN_STRING_QUOTE_END; } YY_BREAK case 177: YY_RULE_SETUP { return (unsigned char)yytext[0]; } YY_BREAK case 178: /* rule 178 can match eol */ YY_RULE_SETUP { return MZN_END_OF_LINE_IN_STRING; } YY_BREAK case YY_STATE_EOF(string): case YY_STATE_EOF(string_quote): { yy_pop_state(yyscanner); return MZN_UNTERMINATED_STRING; } YY_BREAK case 179: YY_RULE_SETUP { yylval->sValue = strdup(yytext+1); yylval->sValue[strlen(yytext)-2] = 0; return MZN_QUOTED_IDENTIFIER; } YY_BREAK case 180: YY_RULE_SETUP { return (unsigned char)yytext[0]; } YY_BREAK case 181: YY_RULE_SETUP ECHO; YY_BREAK case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(multilinecomment): case YY_STATE_EOF(doccomment): case YY_STATE_EOF(doccomment_file): case YY_STATE_EOF(bracket_exp): case YY_STATE_EOF(quoted_exp): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = yyg->yy_hold_char; YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) { /* This was really a NUL. */ yy_state_type yy_next_state; yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( yyscanner ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++yyg->yy_c_buf_p; yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = yyg->yy_c_buf_p; goto yy_find_action; } } else switch ( yy_get_next_buffer( yyscanner ) ) { case EOB_ACT_END_OF_FILE: { yyg->yy_did_buffer_switch_on_eof = 0; if ( yywrap( yyscanner ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( yyscanner ); yy_cp = yyg->yy_c_buf_p; yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: yyg->yy_c_buf_p = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; yy_current_state = yy_get_previous_state( yyscanner ); yy_cp = yyg->yy_c_buf_p; yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of user's declarations */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; char *source = yyg->yytext_ptr; int number_to_move, i; int ret_val; if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; else { int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; int yy_c_buf_p_offset = (int) (yyg->yy_c_buf_p - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc( (void *) b->yy_ch_buf, (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = NULL; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), yyg->yy_n_chars, num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } if ( yyg->yy_n_chars == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart( yyin , yyscanner); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); /* "- 2" to take care of EOB's */ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); } yyg->yy_n_chars += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (yyscan_t yyscanner) { yy_state_type yy_current_state; char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_current_state = yyg->yy_start; for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) { YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 83); if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 500 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) { int yy_is_jam; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ char *yy_cp = yyg->yy_c_buf_p; YY_CHAR yy_c = 83; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 500 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; yy_is_jam = (yy_current_state == 499); (void)yyg; return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_UNPUT static void yyunput (int c, char * yy_bp , yyscan_t yyscanner) { char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_cp = yyg->yy_c_buf_p; /* undo effects of setting up yytext */ *yy_cp = yyg->yy_hold_char; if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ int number_to_move = yyg->yy_n_chars + 2; char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; char *source = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) *--dest = *--source; yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size; if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); } *--yy_cp = (char) c; yyg->yytext_ptr = yy_bp; yyg->yy_hold_char = *yy_cp; yyg->yy_c_buf_p = yy_cp; } #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (yyscan_t yyscanner) #else static int input (yyscan_t yyscanner) #endif { int c; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; *yyg->yy_c_buf_p = yyg->yy_hold_char; if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) /* This was really a NUL. */ *yyg->yy_c_buf_p = '\0'; else { /* need more input */ int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); ++yyg->yy_c_buf_p; switch ( yy_get_next_buffer( yyscanner ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart( yyin , yyscanner); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( yyscanner ) ) return 0; if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(yyscanner); #else return input(yyscanner); #endif } case EOB_ACT_CONTINUE_SCAN: yyg->yy_c_buf_p = yyg->yytext_ptr + offset; break; } } } c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ yyg->yy_hold_char = *++yyg->yy_c_buf_p; return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * @param yyscanner The scanner object. * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (yyscanner); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); } yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner); yy_load_buffer_state( yyscanner ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * @param yyscanner The scanner object. */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (yyscanner); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *yyg->yy_c_buf_p = yyg->yy_hold_char; YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( yyscanner ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ yyg->yy_did_buffer_switch_on_eof = 1; } static void yy_load_buffer_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; yyg->yy_hold_char = *yyg->yy_c_buf_p; } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * @param yyscanner The scanner object. * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer( b, file , yyscanner); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * @param yyscanner The scanner object. */ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree( (void *) b->yy_ch_buf , yyscanner ); yyfree( (void *) b , yyscanner ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) { int oerrno = errno; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_flush_buffer( b , yyscanner); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * @param yyscanner The scanner object. */ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( yyscanner ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * @param yyscanner The scanner object. */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (new_buffer == NULL) return; yyensure_buffer_stack(yyscanner); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *yyg->yy_c_buf_p = yyg->yy_hold_char; YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) yyg->yy_buffer_stack_top++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( yyscanner ); yyg->yy_did_buffer_switch_on_eof = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * @param yyscanner The scanner object. */ void yypop_buffer_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner); YY_CURRENT_BUFFER_LVALUE = NULL; if (yyg->yy_buffer_stack_top > 0) --yyg->yy_buffer_stack_top; if (YY_CURRENT_BUFFER) { yy_load_buffer_state( yyscanner ); yyg->yy_did_buffer_switch_on_eof = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (yyscan_t yyscanner) { yy_size_t num_to_alloc; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (!yyg->yy_buffer_stack) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); if ( ! yyg->yy_buffer_stack ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); yyg->yy_buffer_stack_max = num_to_alloc; yyg->yy_buffer_stack_top = 0; return; } if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ /* Increase the buffer to prepare for a possible push. */ yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = yyg->yy_buffer_stack_max + grow_size; yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc (yyg->yy_buffer_stack, num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); if ( ! yyg->yy_buffer_stack ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); /* zero only the new slots.*/ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); yyg->yy_buffer_stack_max = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return NULL; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = NULL; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer( b , yyscanner ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * @param yyscanner The scanner object. * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) { return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param yybytes the byte buffer to scan * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = (yy_size_t) (_yybytes_len + 2); buf = (char *) yyalloc( n , yyscanner ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer( buf, n , yyscanner); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } static void yy_push_state (int _new_state , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( yyg->yy_start_stack_ptr >= yyg->yy_start_stack_depth ) { yy_size_t new_size; yyg->yy_start_stack_depth += YY_START_STACK_INCR; new_size = (yy_size_t) yyg->yy_start_stack_depth * sizeof( int ); if ( ! yyg->yy_start_stack ) yyg->yy_start_stack = (int *) yyalloc( new_size , yyscanner ); else yyg->yy_start_stack = (int *) yyrealloc( (void *) yyg->yy_start_stack, new_size , yyscanner ); if ( ! yyg->yy_start_stack ) YY_FATAL_ERROR( "out of memory expanding start-condition stack" ); } yyg->yy_start_stack[yyg->yy_start_stack_ptr++] = YY_START; BEGIN(_new_state); } static void yy_pop_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( --yyg->yy_start_stack_ptr < 0 ) YY_FATAL_ERROR( "start-condition stack underflow" ); BEGIN(yyg->yy_start_stack[yyg->yy_start_stack_ptr]); } static int yy_top_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyg->yy_start_stack[yyg->yy_start_stack_ptr - 1]; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = yyg->yy_hold_char; \ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ yyg->yy_hold_char = *yyg->yy_c_buf_p; \ *yyg->yy_c_buf_p = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the user-defined data for this scanner. * @param yyscanner The scanner object. */ YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyextra; } /** Get the current line number. * @param yyscanner The scanner object. */ int yyget_lineno (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (! YY_CURRENT_BUFFER) return 0; return yylineno; } /** Get the current column number. * @param yyscanner The scanner object. */ int yyget_column (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (! YY_CURRENT_BUFFER) return 0; return yycolumn; } /** Get the input stream. * @param yyscanner The scanner object. */ FILE *yyget_in (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyin; } /** Get the output stream. * @param yyscanner The scanner object. */ FILE *yyget_out (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyout; } /** Get the length of the current token. * @param yyscanner The scanner object. */ int yyget_leng (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyleng; } /** Get the current token. * @param yyscanner The scanner object. */ char *yyget_text (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yytext; } /** Set the user-defined data. This data is never touched by the scanner. * @param user_defined The data to be associated with this scanner. * @param yyscanner The scanner object. */ void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyextra = user_defined ; } /** Set the current line number. * @param _line_number line number * @param yyscanner The scanner object. */ void yyset_lineno (int _line_number , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* lineno is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); yylineno = _line_number; } /** Set the current column. * @param _column_no column number * @param yyscanner The scanner object. */ void yyset_column (int _column_no , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* column is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) YY_FATAL_ERROR( "yyset_column called with no buffer" ); yycolumn = _column_no; } /** Set the input stream. This does not discard the current * input buffer. * @param _in_str A readable stream. * @param yyscanner The scanner object. * @see yy_switch_to_buffer */ void yyset_in (FILE * _in_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyin = _in_str ; } void yyset_out (FILE * _out_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyout = _out_str ; } int yyget_debug (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yy_flex_debug; } void yyset_debug (int _bdebug , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_flex_debug = _bdebug ; } /* Accessor methods for yylval and yylloc */ YYSTYPE * yyget_lval (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yylval; } void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yylval = yylval_param; } YYLTYPE *yyget_lloc (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yylloc; } void yyset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yylloc = yylloc_param; } /* User-visible API */ /* yylex_init is special because it creates the scanner itself, so it is * the ONLY reentrant function that doesn't take the scanner as the last argument. * That's why we explicitly handle the declaration, instead of using our macros. */ int yylex_init(yyscan_t* ptr_yy_globals) { if (ptr_yy_globals == NULL){ errno = EINVAL; return 1; } *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); if (*ptr_yy_globals == NULL){ errno = ENOMEM; return 1; } /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); return yy_init_globals ( *ptr_yy_globals ); } /* yylex_init_extra has the same functionality as yylex_init, but follows the * convention of taking the scanner as the last argument. Note however, that * this is a *pointer* to a scanner, as it will be allocated by this call (and * is the reason, too, why this function also must handle its own declaration). * The user defined value in the first argument will be available to yyalloc in * the yyextra field. */ int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals ) { struct yyguts_t dummy_yyguts; yyset_extra (yy_user_defined, &dummy_yyguts); if (ptr_yy_globals == NULL){ errno = EINVAL; return 1; } *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); if (*ptr_yy_globals == NULL){ errno = ENOMEM; return 1; } /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); yyset_extra (yy_user_defined, *ptr_yy_globals); return yy_init_globals ( *ptr_yy_globals ); } static int yy_init_globals (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ yyg->yy_buffer_stack = NULL; yyg->yy_buffer_stack_top = 0; yyg->yy_buffer_stack_max = 0; yyg->yy_c_buf_p = NULL; yyg->yy_init = 0; yyg->yy_start = 0; yyg->yy_start_stack_ptr = 0; yyg->yy_start_stack_depth = 0; yyg->yy_start_stack = NULL; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = NULL; yyout = NULL; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(yyscanner); } /* Destroy the stack itself. */ yyfree(yyg->yy_buffer_stack , yyscanner); yyg->yy_buffer_stack = NULL; /* Destroy the start condition stack. */ yyfree( yyg->yy_start_stack , yyscanner ); yyg->yy_start_stack = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * yylex() is called, initialization will occur. */ yy_init_globals( yyscanner); /* Destroy the main struct (reentrant only). */ yyfree ( yyscanner , yyscanner ); yyscanner = NULL; return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (const char * s , yyscan_t yyscanner) { int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (yy_size_t size , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; return malloc(size); } void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return realloc(ptr, size); } void yyfree (void * ptr , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" namespace MiniZinc { int yy_input_proc(char* buf, int size, yyscan_t yyscanner) { MiniZinc::ParserState* parm = static_cast(yyget_extra(yyscanner)); return parm->fillBuffer(buf, size); // work around warning that yyunput is unused yyunput (0,buf,yyscanner); } } libminizinc-2.4.2/lib/cached/md5_cached.cmake000066400000000000000000000004011360574160400207620ustar00rootroot00000000000000set(lexer_lxx_md5_cached "991ed2e93d928a4fd11c9c7ca1793403") set(parser_yxx_md5_cached "9fe7d1d98610d3004ec1ae8bd87fc6c1") set(regex_lexer_lxx_md5_cached "e1a1ab28ed8f0bf77b83431b404333e8") set(regex_parser_yxx_md5_cached "0cbbb9dcbeac7a1cce98302bda9a8f01")libminizinc-2.4.2/lib/cached/minizinc/000077500000000000000000000000001360574160400176315ustar00rootroot00000000000000libminizinc-2.4.2/lib/cached/minizinc/parser.tab.hh000066400000000000000000000146361360574160400222250ustar00rootroot00000000000000/* A Bison parser, made by GNU Bison 3.1. */ /* Bison interface for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ #ifndef YY_MZN_YY_USERS_TACK_PROGRAMMING_MINIZINC_LIBMZN_BUILD_XCODE_INCLUDE_MINIZINC_PARSER_TAB_HH_INCLUDED # define YY_MZN_YY_USERS_TACK_PROGRAMMING_MINIZINC_LIBMZN_BUILD_XCODE_INCLUDE_MINIZINC_PARSER_TAB_HH_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int mzn_yydebug; #endif /* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { END = 0, MZN_INTEGER_LITERAL = 258, MZN_BOOL_LITERAL = 259, MZN_FLOAT_LITERAL = 260, MZN_IDENTIFIER = 261, MZN_QUOTED_IDENTIFIER = 262, MZN_STRING_LITERAL = 263, MZN_STRING_QUOTE_START = 264, MZN_STRING_QUOTE_MID = 265, MZN_STRING_QUOTE_END = 266, MZN_TI_IDENTIFIER = 267, MZN_TI_ENUM_IDENTIFIER = 268, MZN_DOC_COMMENT = 269, MZN_DOC_FILE_COMMENT = 270, MZN_VAR = 271, MZN_PAR = 272, MZN_ABSENT = 273, MZN_ANN = 274, MZN_ANNOTATION = 275, MZN_ANY = 276, MZN_ARRAY = 277, MZN_BOOL = 278, MZN_CASE = 279, MZN_CONSTRAINT = 280, MZN_DEFAULT = 281, MZN_ELSE = 282, MZN_ELSEIF = 283, MZN_ENDIF = 284, MZN_ENUM = 285, MZN_FLOAT = 286, MZN_FUNCTION = 287, MZN_IF = 288, MZN_INCLUDE = 289, MZN_INFINITY = 290, MZN_INT = 291, MZN_LET = 292, MZN_LIST = 293, MZN_MAXIMIZE = 294, MZN_MINIMIZE = 295, MZN_OF = 296, MZN_OPT = 297, MZN_SATISFY = 298, MZN_OUTPUT = 299, MZN_PREDICATE = 300, MZN_RECORD = 301, MZN_SET = 302, MZN_SOLVE = 303, MZN_STRING = 304, MZN_TEST = 305, MZN_THEN = 306, MZN_TUPLE = 307, MZN_TYPE = 308, MZN_UNDERSCORE = 309, MZN_VARIANT_RECORD = 310, MZN_WHERE = 311, MZN_LEFT_BRACKET = 312, MZN_LEFT_2D_BRACKET = 313, MZN_RIGHT_BRACKET = 314, MZN_RIGHT_2D_BRACKET = 315, FLATZINC_IDENTIFIER = 316, MZN_INVALID_INTEGER_LITERAL = 317, MZN_INVALID_FLOAT_LITERAL = 318, MZN_UNTERMINATED_STRING = 319, MZN_END_OF_LINE_IN_STRING = 320, MZN_INVALID_NULL = 321, MZN_EQUIV = 322, MZN_IMPL = 323, MZN_RIMPL = 324, MZN_OR = 325, MZN_XOR = 326, MZN_AND = 327, MZN_LE = 328, MZN_GR = 329, MZN_LQ = 330, MZN_GQ = 331, MZN_EQ = 332, MZN_NQ = 333, MZN_WEAK_EQ = 334, MZN_IN = 335, MZN_SUBSET = 336, MZN_SUPERSET = 337, MZN_UNION = 338, MZN_DIFF = 339, MZN_SYMDIFF = 340, MZN_DOTDOT = 341, MZN_PLUS = 342, MZN_MINUS = 343, MZN_WEAK_PLUS = 344, MZN_WEAK_MINUS = 345, MZN_MULT = 346, MZN_DIV = 347, MZN_IDIV = 348, MZN_MOD = 349, MZN_INTERSECT = 350, MZN_WEAK_MULT = 351, MZN_POW = 352, MZN_NOT = 353, MZN_PLUSPLUS = 354, MZN_COLONCOLON = 355, PREC_ANNO = 356, MZN_EQUIV_QUOTED = 357, MZN_IMPL_QUOTED = 358, MZN_RIMPL_QUOTED = 359, MZN_OR_QUOTED = 360, MZN_XOR_QUOTED = 361, MZN_AND_QUOTED = 362, MZN_LE_QUOTED = 363, MZN_GR_QUOTED = 364, MZN_LQ_QUOTED = 365, MZN_GQ_QUOTED = 366, MZN_EQ_QUOTED = 367, MZN_NQ_QUOTED = 368, MZN_IN_QUOTED = 369, MZN_SUBSET_QUOTED = 370, MZN_SUPERSET_QUOTED = 371, MZN_UNION_QUOTED = 372, MZN_DIFF_QUOTED = 373, MZN_SYMDIFF_QUOTED = 374, MZN_DOTDOT_QUOTED = 375, MZN_PLUS_QUOTED = 376, MZN_MINUS_QUOTED = 377, MZN_MULT_QUOTED = 378, MZN_DIV_QUOTED = 379, MZN_IDIV_QUOTED = 380, MZN_MOD_QUOTED = 381, MZN_INTERSECT_QUOTED = 382, MZN_POW_QUOTED = 383, MZN_NOT_QUOTED = 384, MZN_COLONCOLON_QUOTED = 385, MZN_PLUSPLUS_QUOTED = 386 }; #endif /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { long long int iValue; char* sValue; bool bValue; double dValue; MiniZinc::Item* item; MiniZinc::VarDecl* vardeclexpr; std::vector* vardeclexpr_v; MiniZinc::TypeInst* tiexpr; std::vector* tiexpr_v; MiniZinc::Expression* expression; std::vector* expression_v; std::vector >* expression_vv; std::vector > >* expression_vvv; MiniZinc::Generator* generator; std::vector* generator_v; std::vector* string_v; std::vector >* expression_p; MiniZinc::Generators* generators; }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif /* Location type. */ #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED typedef struct YYLTYPE YYLTYPE; struct YYLTYPE { int first_line; int first_column; int last_line; int last_column; }; # define YYLTYPE_IS_DECLARED 1 # define YYLTYPE_IS_TRIVIAL 1 #endif int mzn_yyparse (void *parm); #endif /* !YY_MZN_YY_USERS_TACK_PROGRAMMING_MINIZINC_LIBMZN_BUILD_XCODE_INCLUDE_MINIZINC_PARSER_TAB_HH_INCLUDED */ libminizinc-2.4.2/lib/cached/minizinc/support/000077500000000000000000000000001360574160400213455ustar00rootroot00000000000000libminizinc-2.4.2/lib/cached/minizinc/support/regex_parser.tab.hh000066400000000000000000000053651360574160400251320ustar00rootroot00000000000000/* A Bison parser, made by GNU Bison 3.1. */ /* Bison interface for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ #ifndef YY_REGEX_YY_USERS_TACK_PROGRAMMING_MINIZINC_LIBMZN_BUILD_XCODE_INCLUDE_MINIZINC_SUPPORT_REGEX_PARSER_TAB_HH_INCLUDED # define YY_REGEX_YY_USERS_TACK_PROGRAMMING_MINIZINC_LIBMZN_BUILD_XCODE_INCLUDE_MINIZINC_SUPPORT_REGEX_PARSER_TAB_HH_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int regex_yydebug; #endif /* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { R_INTEGER = 258, R_GROUP_OPEN = 259, R_GROUP_CLOSE = 260, R_STAR = 261, R_PLUS = 262, R_ANY = 263, R_UNION = 264, R_OPTIONAL = 265, R_QUANT_OPEN = 266, R_QUANT_CLOSE = 267, R_COMMA = 268, R_CLASS_OPEN = 269, R_CLASS_CLOSE = 270, R_CLASS_RANGE = 271, R_CLASS_NEG = 272, R_IDENTIFIER = 273 }; #endif /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { int iValue; char* sValue; std::set* setValue; Gecode::REG* rValue; }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif extern YYSTYPE regex_yylval; int regex_yyparse (REContext& ctx); #endif /* !YY_REGEX_YY_USERS_TACK_PROGRAMMING_MINIZINC_LIBMZN_BUILD_XCODE_INCLUDE_MINIZINC_SUPPORT_REGEX_PARSER_TAB_HH_INCLUDED */ libminizinc-2.4.2/lib/cached/parser.tab.cpp000066400000000000000000006274301360574160400205720ustar00rootroot00000000000000/* A Bison parser, made by GNU Bison 3.1. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ #define YYBISON_VERSION "3.1" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 1 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Substitute the variable and function names. */ #define yyparse mzn_yyparse #define yylex mzn_yylex #define yyerror mzn_yyerror #define yydebug mzn_yydebug #define yynerrs mzn_yynerrs /* Copy the first part of user declarations. */ #define SCANNER static_cast(parm)->yyscanner #include #include #include #include namespace MiniZinc{ class ParserLocation; } #define YYLTYPE MiniZinc::ParserLocation #define YYLTYPE_IS_DECLARED 1 #define YYLTYPE_IS_TRIVIAL 0 #define YYMAXDEPTH 10000 #define YYINITDEPTH 10000 #include #include using namespace std; using namespace MiniZinc; #define YYLLOC_DEFAULT(Current, Rhs, N) \ Current.filename(Rhs[1].filename()); \ Current.first_line(Rhs[1].first_line()); \ Current.first_column(Rhs[1].first_column()); \ Current.last_line(Rhs[N].last_line()); \ Current.last_column(Rhs[N].last_column()); int mzn_yyparse(void*); int mzn_yylex(YYSTYPE*, YYLTYPE*, void* scanner); int mzn_yylex_init (void** scanner); int mzn_yylex_destroy (void* scanner); int mzn_yyget_lineno (void* scanner); void mzn_yyset_extra (void* user_defined ,void* yyscanner ); extern int yydebug; namespace MiniZinc { void yyerror(YYLTYPE* location, void* parm, const string& str) { ParserState* pp = static_cast(parm); Model* m = pp->model; while (m->parent() != NULL) { m = m->parent(); pp->err << "(included from file '" << m->filename() << "')" << endl; } pp->err << location->toString() << ":" << endl; pp->printCurrentLine(location->first_column(),location->last_column()); pp->err << "Error: " << str << std::endl; pp->hadError = true; pp->syntaxErrors.push_back(SyntaxError(Location(*location), str)); } bool notInDatafile(YYLTYPE* location, void* parm, const string& item) { ParserState* pp = static_cast(parm); if (pp->isDatafile) { yyerror(location,parm,item+" item not allowed in data file"); return false; } return true; } Expression* createDocComment(const ParserLocation& loc, const std::string& s) { std::vector args(1); args[0] = new StringLit(loc, s); Call* c = new Call(Location(loc), constants().ann.doc_comment, args); c->type(Type::ann()); return c; } Expression* createArrayAccess(const ParserLocation& loc, Expression* e, std::vector >& idx) { Expression* ret = e; for (unsigned int i=0; i* vardeclexpr_v; MiniZinc::TypeInst* tiexpr; std::vector* tiexpr_v; MiniZinc::Expression* expression; std::vector* expression_v; std::vector >* expression_vv; std::vector > >* expression_vvv; MiniZinc::Generator* generator; std::vector* generator_v; std::vector* string_v; std::vector >* expression_p; MiniZinc::Generators* generators; }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif /* Location type. */ #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED typedef struct YYLTYPE YYLTYPE; struct YYLTYPE { int first_line; int first_column; int last_line; int last_column; }; # define YYLTYPE_IS_DECLARED 1 # define YYLTYPE_IS_TRIVIAL 1 #endif int mzn_yyparse (void *parm); #endif /* !YY_MZN_YY_USERS_TACK_PROGRAMMING_MINIZINC_LIBMZN_BUILD_XCODE_INCLUDE_MINIZINC_PARSER_TAB_HH_INCLUDED */ /* Copy the second part of user declarations. */ #ifdef short # undef short #endif #ifdef YYTYPE_UINT8 typedef YYTYPE_UINT8 yytype_uint8; #else typedef unsigned char yytype_uint8; #endif #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else typedef unsigned short yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else typedef short yytype_int16; #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif ! defined YYSIZE_T # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned # endif #endif #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE # if (defined __GNUC__ \ && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C # define YY_ATTRIBUTE(Spec) __attribute__(Spec) # else # define YY_ATTRIBUTE(Spec) /* empty */ # endif #endif #ifndef YY_ATTRIBUTE_PURE # define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) #endif #ifndef YY_ATTRIBUTE_UNUSED # define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) #endif #if !defined _Noreturn \ && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) # if defined _MSC_VER && 1200 <= _MSC_VER # define _Noreturn __declspec (noreturn) # else # define _Noreturn YY_ATTRIBUTE ((__noreturn__)) # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(E) ((void) (E)) #else # define YYUSE(E) /* empty */ #endif #if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ /* Suppress an incorrect diagnostic about yylval being uninitialized. */ # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yytype_int16 yyss_alloc; YYSTYPE yyvs_alloc; YYLTYPE yyls_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + 2 * YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 157 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 5058 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 140 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 74 /* YYNRULES -- Number of rules. */ #define YYNRULES 321 /* YYNSTATES -- Number of states. */ #define YYNSTATES 540 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 386 #define YYTRANSLATE(YYX) \ ((unsigned) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex, without out-of-bounds checking. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 135, 136, 2, 2, 137, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 138, 132, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 133, 139, 134, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { 0, 271, 271, 273, 275, 278, 287, 296, 305, 314, 316, 319, 327, 336, 336, 338, 354, 358, 360, 362, 363, 365, 367, 369, 371, 373, 376, 376, 376, 377, 377, 377, 377, 377, 378, 381, 405, 411, 418, 426, 436, 448, 463, 464, 468, 476, 477, 481, 485, 491, 493, 500, 505, 510, 517, 521, 529, 539, 546, 555, 567, 575, 576, 581, 582, 584, 589, 590, 594, 598, 603, 603, 606, 608, 612, 617, 621, 623, 627, 628, 634, 643, 646, 654, 662, 671, 680, 689, 702, 703, 707, 709, 711, 713, 715, 717, 719, 724, 730, 733, 735, 739, 741, 743, 752, 763, 766, 768, 774, 775, 777, 779, 781, 783, 792, 801, 803, 805, 807, 809, 811, 813, 815, 817, 819, 824, 829, 834, 839, 845, 847, 860, 861, 863, 865, 867, 869, 871, 873, 875, 877, 879, 881, 883, 885, 887, 889, 891, 893, 895, 897, 899, 908, 917, 919, 921, 923, 925, 927, 929, 931, 933, 935, 940, 945, 950, 955, 961, 963, 970, 982, 984, 988, 990, 992, 994, 997, 999, 1002, 1004, 1006, 1008, 1010, 1012, 1013, 1016, 1017, 1020, 1021, 1024, 1025, 1028, 1029, 1032, 1033, 1036, 1037, 1038, 1043, 1045, 1051, 1056, 1064, 1071, 1080, 1082, 1087, 1093, 1096, 1099, 1101, 1103, 1109, 1111, 1113, 1121, 1123, 1126, 1129, 1132, 1134, 1138, 1140, 1144, 1146, 1157, 1168, 1208, 1211, 1216, 1223, 1228, 1232, 1238, 1245, 1261, 1262, 1266, 1268, 1270, 1272, 1274, 1276, 1278, 1280, 1282, 1284, 1286, 1288, 1290, 1292, 1294, 1296, 1298, 1300, 1302, 1304, 1306, 1308, 1310, 1312, 1314, 1316, 1318, 1320, 1324, 1332, 1364, 1366, 1367, 1387, 1442, 1445, 1451, 1457, 1459, 1463, 1470, 1479, 1481, 1489, 1491, 1500, 1500, 1503, 1509, 1520, 1521, 1524, 1526, 1530, 1534, 1538, 1540, 1542, 1544, 1546, 1548, 1550, 1552, 1554, 1556, 1558, 1560, 1562, 1564, 1566, 1568, 1570, 1572, 1574, 1576, 1578, 1580, 1582, 1584, 1586, 1588, 1590, 1592, 1594, 1596 }; #endif #if YYDEBUG || YYERROR_VERBOSE || 1 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "\"end of file\"", "error", "$undefined", "\"integer literal\"", "\"bool literal\"", "\"float literal\"", "\"identifier\"", "\"quoted identifier\"", "\"string literal\"", "\"interpolated string start\"", "\"interpolated string middle\"", "\"interpolated string end\"", "\"type-inst identifier\"", "\"type-inst enum identifier\"", "\"documentation comment\"", "\"file-level documentation comment\"", "\"var\"", "\"par\"", "\"<>\"", "\"ann\"", "\"annotation\"", "\"any\"", "\"array\"", "\"bool\"", "\"case\"", "\"constraint\"", "\"default\"", "\"else\"", "\"elseif\"", "\"endif\"", "\"enum\"", "\"float\"", "\"function\"", "\"if\"", "\"include\"", "\"infinity\"", "\"int\"", "\"let\"", "\"list\"", "\"maximize\"", "\"minimize\"", "\"of\"", "\"opt\"", "\"satisfy\"", "\"output\"", "\"predicate\"", "\"record\"", "\"set\"", "\"solve\"", "\"string\"", "\"test\"", "\"then\"", "\"tuple\"", "\"type\"", "\"_\"", "\"variant_record\"", "\"where\"", "\"[\"", "\"[|\"", "\"]\"", "\"|]\"", "FLATZINC_IDENTIFIER", "\"invalid integer literal\"", "\"invalid float literal\"", "\"unterminated string\"", "\"end of line inside string literal\"", "\"null character\"", "\"<->\"", "\"->\"", "\"<-\"", "\"\\\\/\"", "\"xor\"", "\"/\\\\\"", "\"<\"", "\">\"", "\"<=\"", "\">=\"", "\"=\"", "\"!=\"", "\"~=\"", "\"in\"", "\"subset\"", "\"superset\"", "\"union\"", "\"diff\"", "\"symdiff\"", "\"..\"", "\"+\"", "\"-\"", "\"~+\"", "\"~-\"", "\"*\"", "\"/\"", "\"div\"", "\"mod\"", "\"intersect\"", "\"~*\"", "\"^\"", "\"not\"", "\"++\"", "\"::\"", "PREC_ANNO", "\"'<->'\"", "\"'->'\"", "\"'<-'\"", "\"'\\\\/'\"", "\"'xor'\"", "\"'/\\\\'\"", "\"'<'\"", "\"'>'\"", "\"'<='\"", "\"'>='\"", "\"'='\"", "\"'!='\"", "\"'in'\"", "\"'subset'\"", "\"'superset'\"", "\"'union'\"", "\"'diff'\"", "\"'symdiff'\"", "\"'..'\"", "\"'+'\"", "\"'-'\"", "\"'*'\"", "\"'/'\"", "\"'div'\"", "\"'mod'\"", "\"'intersect'\"", "\"'^'\"", "\"'not'\"", "\"'::'\"", "\"'++'\"", "';'", "'{'", "'}'", "'('", "')'", "','", "':'", "'|'", "$accept", "model", "item_list", "item_list_head", "doc_file_comments", "semi_or_none", "item", "item_tail", "error_item_start", "include_item", "vardecl_item", "string_lit_list", "enum_id_list", "assign_item", "constraint_item", "solve_item", "output_item", "predicate_item", "function_item", "annotation_item", "operation_item_tail", "params", "params_list", "params_list_head", "comma_or_none", "ti_expr_and_id_or_anon", "ti_expr_and_id", "ti_expr_list", "ti_expr_list_head", "ti_expr", "base_ti_expr", "opt_opt", "base_ti_expr_tail", "array_access_expr_list", "array_access_expr_list_head", "array_access_expr", "expr_list", "expr_list_head", "set_expr", "expr", "expr_atom_head", "expr_atom_head_nonstring", "string_expr", "string_quote_rest", "array_access_tail", "set_literal", "set_comp", "comp_tail", "generator_list", "generator_list_head", "generator", "generator_eq", "id_list", "id_list_head", "simple_array_literal", "simple_array_literal_2d", "simple_array_literal_3d_list", "simple_array_literal_2d_list", "simple_array_comp", "if_then_else_expr", "elseif_list", "quoted_op", "quoted_op_call", "call_expr", "comp_or_expr", "comp_or_expr_head", "let_expr", "let_vardecl_item_list", "comma_or_semi", "let_vardecl_item", "annotations", "annotation_expr", "ne_annotations", "id_or_quoted_op", YY_NULLPTR }; #endif # ifdef YYPRINT /* YYTOKNUM[NUM] -- (External) token number corresponding to the (internal) symbol number NUM (which must be that of a token). */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 59, 123, 125, 40, 41, 44, 58, 124 }; # endif #define YYPACT_NINF -402 #define yypact_value_is_default(Yystate) \ (!!((Yystate) == (-402))) #define YYTABLE_NINF -89 #define yytable_value_is_error(Yytable_value) \ (!!((Yytable_value) == (-89))) /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int16 yypact[] = { 823, -103, -402, -402, -402, -8, -402, 3485, -402, -402, 1623, -402, -9, -9, -402, -402, 33, -1, -402, 2820, 51, -402, 2155, 3485, 55, -402, -402, -74, 25, 2687, 3485, 59, -32, -402, 73, 23, 2953, 532, 3618, 3618, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -53, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, 3086, 3485, 83, -402, -47, 1357, 219, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -32, -48, -402, 48, -402, 3706, -402, -402, -402, 23, 23, 23, 23, 23, 23, -44, -402, 23, -402, 1490, 3219, 3485, 1090, 40, -29, 3485, 3485, 3485, -37, 11, 4739, -402, -402, -402, -402, 2421, 2554, -34, 2155, 44, 4739, 28, -36, 4458, -402, 1889, 2288, -402, 4739, -34, 3653, 2, 4, -34, 40, -402, 54, 14, 3741, -402, 686, -402, -2, -30, 31, 31, 3485, -402, 21, 3776, 4026, -402, 1224, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, 35, 152, 118, 3618, 3618, 3618, 3618, 3618, 3618, 3618, 3618, 3618, 3618, 3618, 3618, 3618, 3618, 3618, 3618, 3618, 3618, 3653, 40, 40, 40, 40, 40, 40, 3485, 40, -402, 3485, 101, 26, -402, 4776, 4739, -402, 4500, 30, 37, 3219, 41, 41, 41, 3485, 3485, -402, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3485, 3653, 120, -402, 121, -402, 956, 88, 108, 43, -402, 3485, 10, 3903, 3485, -402, -32, 45, -97, -402, -402, -32, -402, -402, -402, 3485, 3485, -402, 3653, -32, -402, 3485, -402, 162, -402, 38, -402, 46, -402, 3352, 3901, -402, 162, 23, 1357, -402, 3485, 47, 2687, 87, 3800, 29, 29, 29, 277, 53, 53, 53, 53, 39, 39, 39, 39, 29, 39, 31, 8, -402, 3867, 4739, -402, 3219, -402, 3485, 3485, 58, 3485, -402, 130, 3992, -402, 4739, 90, 4830, 4867, 4867, 4921, 4921, 809, 4958, 4958, 4958, 4958, 4958, 4958, 4958, 4050, 4050, 4050, 507, 507, 507, 659, 79, 79, 79, 79, 57, 57, 57, 57, 507, 57, 41, 24, -402, 2687, 2687, 56, 60, 63, -402, -402, 45, 3485, 154, 2022, -402, 4739, 62, 229, 232, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -34, 4401, 163, 235, -402, 167, -402, 1756, 166, 4739, 4739, -402, 166, 175, 195, -402, 119, -402, 199, 178, 124, 3485, 3485, -402, -402, 3485, 128, 40, -402, 4739, 2022, -402, -402, 3485, -402, 4739, 3485, 4552, -402, 3485, -402, -402, -402, -402, 2022, -402, 4739, 2288, -402, 3485, -402, -27, -402, -90, -32, -402, 27, 3485, -402, 3485, 186, -402, -402, 3485, -402, -402, 3485, -402, 162, -402, 3485, 3485, 262, -402, 131, 4117, -402, 136, 4151, 4242, 3485, 4276, -402, -402, 4367, -402, 265, -402, 268, 166, 3485, 3485, 4739, 4739, 3485, 4739, 4739, -402, 220, 4739, 4594, -402, 3485, -402, -32, -402, -402, 4739, -402, -402, -402, -402, -402, 4685, 4648, 4739, 3485, 3485, 166, -402, 3485, 4739, 4739, -402, 4739 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_uint16 yydefact[] = { 0, 0, 179, 178, 181, 174, 198, 0, 96, 97, 88, 11, 88, 88, 182, 94, 0, 0, 91, 0, 0, 92, 88, 0, 0, 180, 90, 0, 0, 89, 0, 0, 286, 93, 0, 176, 0, 0, 0, 0, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 0, 255, 256, 257, 259, 260, 261, 262, 258, 264, 263, 0, 0, 0, 2, 13, 88, 5, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 286, 0, 78, 0, 81, 95, 108, 170, 171, 183, 185, 187, 189, 191, 193, 0, 268, 196, 195, 88, 0, 0, 0, 175, 174, 0, 0, 0, 0, 0, 106, 131, 199, 15, 89, 0, 0, 63, 88, 0, 49, 38, 0, 0, 35, 88, 88, 82, 54, 63, 0, 0, 287, 63, 177, 221, 0, 70, 106, 223, 0, 230, 0, 0, 129, 130, 0, 204, 0, 106, 0, 1, 14, 4, 12, 6, 34, 29, 27, 32, 26, 28, 31, 30, 33, 9, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 184, 186, 188, 190, 192, 194, 0, 197, 10, 102, 0, 70, 99, 101, 48, 267, 272, 0, 70, 0, 168, 169, 167, 0, 0, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 83, 0, 59, 0, 70, 76, 0, 0, 0, 0, 279, 286, 0, 0, 278, 80, 286, 288, 289, 290, 0, 0, 51, 0, 286, 222, 71, 105, 0, 227, 0, 226, 0, 224, 0, 0, 205, 0, 172, 88, 7, 0, 74, 0, 128, 127, 110, 111, 112, 113, 117, 118, 124, 125, 119, 120, 121, 122, 115, 126, 123, 116, 109, 0, 103, 202, 71, 98, 104, 0, 269, 71, 271, 0, 0, 201, 107, 166, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 165, 145, 146, 147, 148, 149, 150, 151, 155, 156, 162, 163, 157, 158, 159, 160, 153, 164, 161, 154, 132, 0, 0, 0, 0, 70, 68, 72, 73, 0, 0, 71, 75, 50, 0, 42, 45, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 316, 317, 318, 319, 315, 320, 321, 63, 235, 284, 0, 283, 0, 282, 88, 61, 53, 52, 291, 61, 219, 0, 207, 70, 209, 210, 0, 70, 228, 0, 225, 231, 0, 0, 173, 8, 37, 66, 85, 266, 0, 100, 273, 0, 274, 203, 0, 87, 86, 65, 64, 71, 67, 60, 88, 77, 0, 43, 0, 46, 0, 286, 233, 0, 0, 74, 0, 0, 281, 280, 0, 55, 56, 0, 232, 71, 208, 0, 0, 71, 218, 0, 0, 206, 0, 0, 0, 0, 0, 69, 79, 0, 40, 0, 39, 0, 61, 0, 0, 285, 276, 0, 62, 217, 212, 213, 211, 215, 220, 229, 114, 286, 265, 270, 275, 152, 41, 44, 47, 57, 0, 0, 277, 0, 0, 61, 234, 0, 214, 216, 58, 236 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { -402, -402, -402, -402, 117, -402, -62, 267, -402, -402, -402, -402, -402, -402, -123, -402, -402, -402, -402, -402, -401, -121, -167, -402, -185, -178, -125, -402, -402, -17, -130, 49, -22, 69, -402, -41, -35, 18, 342, -19, 317, -117, -112, 67, -25, -402, -402, -7, -402, -402, -197, -196, -402, -402, -402, -402, -402, -137, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -402, -133, -83, -170, -402, -402 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { -1, 71, 72, 73, 74, 159, 75, 76, 171, 77, 78, 466, 468, 79, 80, 81, 82, 83, 84, 85, 479, 260, 372, 373, 285, 374, 86, 261, 262, 87, 88, 89, 90, 204, 205, 206, 147, 143, 91, 116, 117, 93, 94, 118, 109, 95, 96, 429, 430, 431, 432, 433, 434, 435, 97, 98, 148, 149, 99, 100, 471, 101, 102, 103, 211, 212, 104, 271, 422, 272, 137, 277, 138, 415 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { 126, 142, 273, 172, 129, 128, 269, 133, 268, 288, 140, 134, 161, 264, 274, 175, 382, 144, 282, 275, 325, 218, 219, 320, 276, 115, 480, 330, 106, 105, 291, 221, 500, 120, 154, 419, 175, 420, 175, 123, 421, 278, 279, 202, 502, 280, 175, 503, 221, 106, 155, 156, 6, 7, 505, 506, 124, 127, 289, 131, 175, 121, 122, 130, 221, 135, 132, 383, 136, 107, 194, 195, 196, 197, 198, 199, 275, 380, 201, 139, 106, 276, 152, 157, 368, 158, 221, 207, 208, 210, 173, 200, 214, 215, 216, 174, 298, 213, 217, 256, 258, 259, 266, 527, 281, 265, 108, 263, 193, 292, 501, 426, 299, 283, 270, 180, 181, 182, 183, 184, 185, 186, 187, 188, 254, 190, 191, 108, 192, 193, 192, 193, 538, 293, 375, 290, 191, 275, 192, 193, 253, 254, 276, 384, 185, 186, 187, 188, 220, 190, 191, 284, 192, 193, 252, 294, 253, 254, 300, 301, 323, 369, 370, 324, 275, 377, 328, 378, 428, 276, 246, 247, 248, 249, 329, 251, 252, 436, 253, 254, 379, 321, 445, 418, 322, 437, 417, 193, 460, 453, 254, 423, 457, 451, 207, 462, 458, 464, 332, 427, 459, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 443, 115, 465, 467, 162, 472, 473, 376, 478, 163, 381, 484, 474, 416, 164, 488, 165, 481, 166, 482, 485, 483, 439, 486, 424, 425, 487, 491, 167, 168, 334, 509, 169, 516, 170, 517, 442, 519, 525, 526, 297, 531, 119, 492, 446, 444, 497, 331, 449, 175, 333, 512, 513, 441, 477, 0, 0, 0, 0, 469, 0, 0, 269, 0, 476, 489, 0, 0, 0, 0, 207, 0, 355, 450, 0, 452, 0, 0, 0, 0, 0, 0, 92, 0, 0, 375, 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, 0, 498, 0, 375, 0, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 92, 455, 456, 0, 0, 0, 0, 0, 0, 92, 92, 0, 461, 0, 0, 0, 463, -89, 181, 182, 183, 184, 185, 186, 187, 188, 0, 190, 191, 0, 192, 193, 0, 0, 150, 151, 0, 0, 0, 0, 504, 0, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 439, 0, 0, 0, 270, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 490, 92, 0, 0, 0, 0, 0, 376, 493, 0, 0, 494, 0, 0, 496, 533, 0, 92, 92, 0, 92, 376, 0, 0, 499, 0, 0, 92, 92, 0, 0, 0, 507, 0, 508, 0, 0, 0, 510, 0, 0, 511, 0, 0, 0, 514, 515, 0, 0, 0, 0, 0, 0, 0, 92, 522, 0, 0, 0, 0, 0, 439, 0, 0, 0, 528, 529, 0, 0, 530, 0, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 0, 0, 536, 537, 221, 0, 539, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 2, 3, 4, 110, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 25, 0, 27, 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 36, 37, 0, 145, 241, 242, 243, 244, 245, 246, 247, 248, 249, 0, 251, 252, 0, 253, 254, 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, 92, 111, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 114, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 221, 70, 0, 0, 0, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 92, 0, 2, 3, 4, 110, 0, 6, 7, 92, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 25, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 35, 0, 0, 36, 37, -89, 242, 243, 244, 245, 246, 247, 248, 249, 0, 251, 252, 0, 253, 254, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 112, 0, 92, 0, 0, 92, 0, 0, 0, 0, 113, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 114, 59, 60, 61, 62, 63, 64, 65, 66, 67, 221, 68, 0, 69, 0, 70, 0, -3, 1, 287, 2, 3, 4, 5, 0, 6, 7, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 17, 18, 0, 19, 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 0, 0, 0, 29, 0, 30, 31, 0, -88, 32, 33, 34, 0, 0, 0, 35, 0, 0, 36, 37, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 0, 253, 254, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 371, 70, 2, 3, 4, 110, 0, 6, 7, 0, 0, 8, 9, 0, 0, 12, 13, 14, 15, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 21, 0, 23, 0, 25, 26, 27, 28, 0, 0, 0, 29, 0, 0, 0, 0, -88, 0, 33, 0, 0, 0, 0, 35, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 0, 70, -66, 2, 3, 4, 110, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 25, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 114, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 0, 70, 209, 2, 3, 4, 5, 0, 6, 7, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 17, 18, 0, 19, 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 0, 0, 0, 29, 0, 30, 31, 0, -88, 32, 33, 34, 0, 0, 0, 35, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 0, 70, 2, 3, 4, 5, 0, 6, 7, 0, 0, 8, 9, 10, 160, 12, 13, 14, 15, 16, 0, 17, 18, 0, 19, 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 0, 0, 0, 29, 0, 30, 31, 0, 0, 32, 33, 34, 0, 0, 0, 35, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 0, 70, 2, 3, 4, 5, 0, 6, 7, 0, 0, 8, 9, 10, 0, 12, 13, 14, 15, 16, 0, 17, 18, 0, 19, 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 0, 0, 0, 29, 0, 30, 31, 0, 0, 32, 33, 34, 0, 0, 0, 35, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 0, 70, 2, 3, 4, 5, 0, 6, 7, 0, 0, 8, 9, 0, 0, 12, 13, 14, 15, 16, 0, 17, 18, 0, 19, 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 0, 0, 0, 29, 0, 30, 31, 0, 0, 32, 33, 34, 0, 0, 0, 35, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 0, 70, 2, 3, 4, 110, 0, 6, 7, 0, 0, 8, 9, 0, 0, 12, 13, 14, 15, 0, 0, 17, 18, 0, 19, 0, 0, 0, 0, 0, 21, 0, 23, 0, 25, 26, 27, 28, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 35, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 475, 70, 2, 3, 4, 110, 0, 6, 7, 0, 0, 8, 9, 0, 0, 12, 13, 14, 15, 0, 0, 17, 18, 0, 19, 0, 0, 0, 0, 0, 21, 0, 23, 0, 25, 26, 27, 28, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 35, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 0, 70, 2, 3, 4, 110, 0, 6, 7, 0, 0, 8, 9, 0, 0, 12, 13, 14, 15, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 21, 0, 23, 0, 25, 26, 27, 28, 0, 0, 0, 29, 0, 0, 0, 0, -88, 0, 33, 0, 0, 0, 0, 35, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 0, 70, 2, 3, 4, 110, 0, 6, 7, 0, 0, 8, 9, 0, 0, 12, 13, 14, 15, 0, 0, 17, 18, 0, 0, 0, 0, 0, 0, 0, 21, 0, 23, 0, 25, 26, 27, 28, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 35, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 0, 70, 2, 3, 4, 110, 0, 6, 7, 0, 0, 8, 9, 0, 0, 12, 13, 14, 15, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 21, 0, 23, 0, 25, 26, 27, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 35, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 0, 70, 2, 3, 4, 110, 0, 6, 7, 0, 0, 8, 9, 0, 0, 0, 0, 14, 15, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 21, 0, 23, 0, 25, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 33, 0, 0, 0, 0, 35, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 0, 70, 2, 3, 4, 110, 0, 6, 7, 0, 0, 8, 9, 0, 0, 0, 0, 14, 15, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 21, 0, 23, 0, 25, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 257, 0, 33, 0, 0, 0, 0, 35, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 0, 70, 2, 3, 4, 110, 0, 6, 7, 0, 0, 8, 9, 0, 0, 0, 0, 14, 15, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 21, 0, 23, 0, 25, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 35, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 0, 70, 2, 3, 4, 110, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 25, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 125, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 114, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 0, 70, 2, 3, 4, 110, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 25, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 36, 37, 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 114, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 0, 70, 2, 3, 4, 110, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 25, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 114, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 153, 70, 2, 3, 4, 110, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 25, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 203, 111, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 114, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 0, 70, 2, 3, 4, 110, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 25, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 36, 37, 0, 438, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 114, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 0, 70, 2, 3, 4, 110, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 25, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 114, 59, 60, 61, 62, 63, 64, 65, 66, 67, 0, 68, 0, 69, 0, 70, 2, 3, 4, 110, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 25, 0, 27, 2, 3, 4, 110, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 14, 35, 0, 0, 36, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 25, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 35, 0, 0, 36, 37, 0, 175, 0, 0, 0, 0, 0, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 221, 68, 0, 69, 0, 70, 0, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 0, 59, 60, 61, 62, 63, 64, 65, 66, 67, 221, 68, 176, 69, 0, 70, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 0, 192, 193, 175, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 0, 253, 254, 0, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 221, 253, 254, 0, 0, -89, 286, 0, 0, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 0, 192, 193, 0, 0, 0, 0, 0, 0, 0, 221, 385, 0, 0, 0, 0, 0, 295, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 0, 253, 254, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 221, 253, 254, 0, 447, 448, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 221, 414, 0, 0, 0, 440, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 0, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 0, 253, 254, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 221, 253, 254, 0, 0, 454, -89, -89, -89, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 0, 253, 254, 0, 0, 0, 0, 0, 0, 0, 221, 0, 0, 0, 296, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 0, 253, 254, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 221, 253, 254, 0, 518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 0, 0, 0, 520, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 0, 253, 254, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 221, 253, 254, 0, 521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 0, 0, 0, 523, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 470, 0, 0, 0, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 221, 253, 254, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 0, 253, 254, 0, 524, 0, 0, 0, 221, 0, 267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 327, 253, 254, 221, 0, 0, 0, 0, 0, 0, 0, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 0, 253, 254, 221, 0, 0, 0, 0, 0, 0, 495, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 532, 253, 254, 0, 0, 221, 0, 0, 0, 0, 0, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 221, 253, 254, 0, 0, 0, 0, 535, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 534, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 221, 253, 254, 0, 0, 0, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 221, 253, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 221, 253, 254, 0, 0, 0, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 326, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 221, 253, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 221, 253, 254, 0, 0, 0, 0, 0, 0, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 221, 253, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 0, 253, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, -89, -89, -89, -89, -89, -89, -89, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 0, 253, 254 }; static const yytype_int16 yycheck[] = { 19, 36, 132, 86, 23, 22, 131, 29, 131, 146, 35, 30, 74, 125, 135, 7, 6, 36, 139, 136, 205, 10, 11, 193, 136, 7, 427, 212, 57, 132, 60, 7, 59, 42, 69, 132, 7, 134, 7, 6, 137, 39, 40, 105, 134, 43, 7, 137, 7, 57, 69, 70, 8, 9, 27, 28, 57, 6, 60, 133, 7, 12, 13, 8, 7, 6, 41, 57, 100, 77, 95, 96, 97, 98, 99, 100, 193, 262, 103, 6, 57, 193, 135, 0, 254, 132, 7, 106, 107, 108, 138, 135, 111, 112, 113, 47, 158, 57, 135, 121, 122, 135, 138, 504, 100, 77, 135, 124, 100, 139, 137, 281, 77, 59, 131, 86, 87, 88, 89, 90, 91, 92, 93, 94, 100, 96, 97, 135, 99, 100, 99, 100, 533, 152, 259, 137, 97, 254, 99, 100, 99, 100, 254, 133, 91, 92, 93, 94, 137, 96, 97, 137, 99, 100, 97, 134, 99, 100, 6, 41, 59, 41, 41, 137, 281, 77, 136, 59, 6, 281, 91, 92, 93, 94, 137, 96, 97, 139, 99, 100, 137, 200, 135, 138, 203, 139, 269, 100, 373, 59, 100, 274, 136, 135, 213, 41, 136, 135, 217, 282, 137, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 297, 218, 8, 6, 20, 77, 6, 259, 77, 25, 264, 431, 80, 267, 30, 435, 32, 77, 34, 59, 56, 137, 292, 80, 278, 279, 137, 134, 44, 45, 284, 80, 48, 6, 50, 139, 296, 136, 8, 6, 158, 56, 10, 445, 301, 299, 459, 213, 324, 7, 218, 483, 483, 295, 422, -1, -1, -1, -1, 415, -1, -1, 422, -1, 422, 437, -1, -1, -1, -1, 324, -1, 326, 327, -1, 329, -1, -1, -1, -1, -1, -1, 0, -1, -1, 445, -1, -1, -1, -1, -1, -1, 10, -1, -1, -1, -1, 462, -1, 459, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, 369, 370, -1, -1, -1, -1, -1, -1, 38, 39, -1, 377, -1, -1, -1, 379, 86, 87, 88, 89, 90, 91, 92, 93, 94, -1, 96, 97, -1, 99, 100, -1, -1, 38, 39, -1, -1, -1, -1, 469, -1, -1, -1, -1, 74, -1, -1, -1, -1, -1, -1, -1, -1, -1, 436, -1, -1, -1, 422, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 440, 105, -1, -1, -1, -1, -1, 445, 448, -1, -1, 451, -1, -1, 454, 519, -1, 121, 122, -1, 124, 459, -1, -1, 464, -1, -1, 131, 132, -1, -1, -1, 472, -1, 474, -1, -1, -1, 478, -1, -1, 481, -1, -1, -1, 485, 486, -1, -1, -1, -1, -1, -1, -1, 158, 495, -1, -1, -1, -1, -1, 517, -1, -1, -1, 505, 506, -1, -1, 509, -1, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, -1, -1, 531, 532, 7, -1, 535, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 3, 4, 5, 6, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, 35, -1, 37, -1, -1, -1, -1, -1, -1, 259, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, 57, 58, -1, 60, 86, 87, 88, 89, 90, 91, 92, 93, 94, -1, 96, 97, -1, 99, 100, -1, -1, -1, -1, -1, -1, 297, -1, -1, -1, 301, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, 98, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, 7, 135, -1, -1, -1, 139, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 369, 370, -1, 3, 4, 5, 6, -1, 8, 9, 379, -1, -1, -1, -1, -1, -1, -1, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, 35, -1, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 422, 54, -1, -1, 57, 58, 86, 87, 88, 89, 90, 91, 92, 93, 94, -1, 96, 97, -1, 99, 100, -1, -1, 445, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, 459, -1, -1, 462, -1, -1, -1, -1, 98, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 7, 131, -1, 133, -1, 135, -1, 0, 1, 139, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, 13, 14, 15, 16, 17, 18, 19, 20, -1, 22, 23, -1, 25, -1, -1, -1, -1, 30, 31, 32, 33, 34, 35, 36, 37, 38, -1, -1, -1, 42, -1, 44, 45, -1, 47, 48, 49, 50, -1, -1, -1, 54, -1, -1, 57, 58, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, -1, 99, 100, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, 1, 135, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, 13, -1, -1, 16, 17, 18, 19, -1, -1, 22, 23, -1, -1, -1, -1, -1, -1, -1, 31, -1, 33, -1, 35, 36, 37, 38, -1, -1, -1, 42, -1, -1, -1, -1, 47, -1, 49, -1, -1, -1, -1, 54, -1, -1, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, -1, 135, 136, 3, 4, 5, 6, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, 35, -1, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, 98, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, -1, 135, 136, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, 13, 14, 15, 16, 17, 18, 19, 20, -1, 22, 23, -1, 25, -1, -1, -1, -1, 30, 31, 32, 33, 34, 35, 36, 37, 38, -1, -1, -1, 42, -1, 44, 45, -1, 47, 48, 49, 50, -1, -1, -1, 54, -1, -1, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, -1, 135, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, 13, 14, 15, 16, 17, 18, 19, 20, -1, 22, 23, -1, 25, -1, -1, -1, -1, 30, 31, 32, 33, 34, 35, 36, 37, 38, -1, -1, -1, 42, -1, 44, 45, -1, -1, 48, 49, 50, -1, -1, -1, 54, -1, -1, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, -1, 135, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, 13, 14, -1, 16, 17, 18, 19, 20, -1, 22, 23, -1, 25, -1, -1, -1, -1, 30, 31, 32, 33, 34, 35, 36, 37, 38, -1, -1, -1, 42, -1, 44, 45, -1, -1, 48, 49, 50, -1, -1, -1, 54, -1, -1, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, -1, 135, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, 13, -1, -1, 16, 17, 18, 19, 20, -1, 22, 23, -1, 25, -1, -1, -1, -1, 30, 31, 32, 33, 34, 35, 36, 37, 38, -1, -1, -1, 42, -1, 44, 45, -1, -1, 48, 49, 50, -1, -1, -1, 54, -1, -1, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, -1, 135, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, 13, -1, -1, 16, 17, 18, 19, -1, -1, 22, 23, -1, 25, -1, -1, -1, -1, -1, 31, -1, 33, -1, 35, 36, 37, 38, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, 49, -1, -1, -1, -1, 54, -1, -1, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, 134, 135, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, 13, -1, -1, 16, 17, 18, 19, -1, -1, 22, 23, -1, 25, -1, -1, -1, -1, -1, 31, -1, 33, -1, 35, 36, 37, 38, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, 49, -1, -1, -1, -1, 54, -1, -1, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, -1, 135, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, 13, -1, -1, 16, 17, 18, 19, -1, -1, 22, 23, -1, -1, -1, -1, -1, -1, -1, 31, -1, 33, -1, 35, 36, 37, 38, -1, -1, -1, 42, -1, -1, -1, -1, 47, -1, 49, -1, -1, -1, -1, 54, -1, -1, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, -1, 135, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, 13, -1, -1, 16, 17, 18, 19, -1, -1, 22, 23, -1, -1, -1, -1, -1, -1, -1, 31, -1, 33, -1, 35, 36, 37, 38, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, 49, -1, -1, -1, -1, 54, -1, -1, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, -1, 135, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, 13, -1, -1, 16, 17, 18, 19, -1, -1, -1, 23, -1, -1, -1, -1, -1, -1, -1, 31, -1, 33, -1, 35, 36, 37, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, 49, -1, -1, -1, -1, 54, -1, -1, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, -1, 135, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, 13, -1, -1, -1, -1, 18, 19, -1, -1, -1, 23, -1, -1, -1, -1, -1, -1, -1, 31, -1, 33, -1, 35, 36, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, 47, -1, 49, -1, -1, -1, -1, 54, -1, -1, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, -1, 135, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, 13, -1, -1, -1, -1, 18, 19, -1, -1, -1, 23, -1, -1, -1, -1, -1, -1, -1, 31, -1, 33, -1, 35, 36, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, 47, -1, 49, -1, -1, -1, -1, 54, -1, -1, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, -1, 135, 3, 4, 5, 6, -1, 8, 9, -1, -1, 12, 13, -1, -1, -1, -1, 18, 19, -1, -1, -1, 23, -1, -1, -1, -1, -1, -1, -1, 31, -1, 33, -1, 35, 36, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 49, -1, -1, -1, -1, 54, -1, -1, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, -1, 135, 3, 4, 5, 6, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, 35, -1, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, 98, -1, 100, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, -1, 135, 3, 4, 5, 6, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, 35, -1, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, 57, 58, 59, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, 98, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, -1, 135, 3, 4, 5, 6, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, 35, -1, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, 98, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, 134, 135, 3, 4, 5, 6, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, 35, -1, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 86, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, 98, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, -1, 135, 3, 4, 5, 6, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, 35, -1, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, 57, 58, -1, 60, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, 98, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, -1, 135, 3, 4, 5, 6, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, 35, -1, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, 98, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, -1, 131, -1, 133, -1, 135, 3, 4, 5, 6, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, 35, -1, 37, 3, 4, 5, 6, -1, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, 18, 54, -1, -1, 57, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, 35, -1, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 88, 54, -1, -1, 57, 58, -1, 7, -1, -1, -1, -1, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 7, 131, -1, 133, -1, 135, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, -1, 121, 122, 123, 124, 125, 126, 127, 128, 129, 7, 131, 79, 133, -1, 135, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, -1, 99, 100, 7, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, -1, 99, 100, -1, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 7, 99, 100, -1, -1, 79, 139, -1, -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, -1, 99, 100, -1, -1, -1, -1, -1, -1, -1, 7, 6, -1, -1, -1, -1, -1, 139, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, -1, 99, 100, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 7, 99, 100, -1, 136, 137, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 7, 131, -1, -1, -1, 137, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, -1, 99, 100, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 7, 99, 100, -1, -1, 137, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, -1, 99, 100, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, 136, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, -1, 99, 100, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 7, 99, 100, -1, 136, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, 136, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, -1, 99, 100, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 7, 99, 100, -1, 136, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, 136, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 7, 99, 100, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, -1, 99, 100, -1, 136, -1, -1, -1, 7, -1, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 56, 99, 100, 7, -1, -1, -1, -1, -1, -1, -1, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, -1, 99, 100, 7, -1, -1, -1, -1, -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 56, 99, 100, -1, -1, 7, -1, -1, -1, -1, -1, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 7, 99, 100, -1, -1, -1, -1, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 29, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 7, 99, 100, -1, -1, -1, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 7, 99, 100, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 7, 99, 100, -1, -1, -1, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 7, 99, 100, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 7, 99, 100, -1, -1, -1, -1, -1, -1, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 7, 99, 100, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, -1, 99, 100, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, -1, 99, 100 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 1, 3, 4, 5, 6, 8, 9, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 25, 30, 31, 32, 33, 34, 35, 36, 37, 38, 42, 44, 45, 48, 49, 50, 54, 57, 58, 87, 88, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 131, 133, 135, 141, 142, 143, 144, 146, 147, 149, 150, 153, 154, 155, 156, 157, 158, 159, 166, 169, 170, 171, 172, 178, 180, 181, 182, 185, 186, 194, 195, 198, 199, 201, 202, 203, 206, 132, 57, 77, 135, 184, 6, 87, 88, 98, 120, 177, 179, 180, 183, 147, 42, 171, 171, 6, 57, 100, 179, 6, 169, 179, 8, 133, 41, 172, 179, 6, 100, 210, 212, 6, 184, 59, 176, 177, 179, 60, 139, 176, 196, 197, 178, 178, 135, 134, 176, 179, 179, 0, 132, 145, 15, 146, 20, 25, 30, 32, 34, 44, 45, 48, 50, 148, 210, 138, 47, 7, 79, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 99, 100, 184, 184, 184, 184, 184, 184, 135, 184, 146, 86, 173, 174, 175, 179, 179, 136, 179, 204, 205, 57, 179, 179, 179, 135, 10, 11, 137, 7, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 99, 100, 47, 172, 47, 172, 135, 161, 167, 168, 169, 182, 77, 138, 51, 154, 166, 169, 207, 209, 170, 161, 181, 182, 211, 39, 40, 43, 100, 161, 59, 137, 164, 139, 139, 197, 60, 137, 60, 139, 179, 134, 139, 136, 144, 146, 77, 6, 41, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 211, 179, 179, 59, 137, 164, 86, 56, 136, 137, 164, 173, 179, 183, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 211, 41, 41, 1, 162, 163, 165, 166, 169, 77, 59, 137, 164, 179, 6, 57, 133, 6, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 131, 213, 179, 210, 138, 132, 134, 137, 208, 210, 179, 179, 211, 210, 6, 187, 188, 189, 190, 191, 192, 193, 139, 139, 60, 176, 137, 187, 184, 146, 179, 135, 172, 136, 137, 175, 179, 135, 179, 59, 137, 172, 172, 136, 136, 137, 164, 179, 41, 169, 135, 8, 151, 6, 152, 161, 29, 200, 77, 6, 80, 134, 154, 209, 77, 160, 160, 77, 59, 137, 164, 56, 80, 137, 164, 197, 179, 134, 162, 179, 179, 56, 179, 165, 170, 179, 59, 137, 134, 137, 210, 27, 28, 179, 179, 80, 179, 179, 190, 191, 179, 179, 6, 139, 136, 136, 136, 136, 179, 136, 136, 8, 6, 160, 179, 179, 179, 56, 56, 210, 29, 51, 179, 179, 160, 179 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { 0, 140, 141, 142, 142, 143, 143, 143, 143, 143, 143, 144, 144, 145, 145, 146, 146, 147, 147, 147, 147, 147, 147, 147, 147, 147, 148, 148, 148, 148, 148, 148, 148, 148, 148, 149, 150, 150, 150, 150, 150, 150, 151, 151, 151, 152, 152, 152, 153, 154, 154, 155, 155, 155, 156, 157, 157, 158, 158, 159, 159, 160, 160, 161, 161, 161, 162, 162, 163, 163, 164, 164, 165, 165, 166, 167, 168, 168, 169, 169, 169, 170, 170, 170, 170, 170, 170, 170, 171, 171, 172, 172, 172, 172, 172, 172, 172, 172, 173, 174, 174, 175, 175, 175, 175, 176, 177, 177, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 180, 180, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 182, 182, 183, 183, 184, 184, 185, 185, 186, 187, 188, 189, 189, 189, 189, 189, 189, 190, 190, 191, 192, 193, 193, 194, 194, 195, 195, 195, 195, 196, 196, 196, 197, 197, 198, 199, 199, 200, 200, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 202, 202, 203, 203, 203, 203, 204, 205, 205, 205, 205, 206, 206, 207, 207, 207, 207, 208, 208, 209, 209, 210, 210, 211, 211, 212, 212, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 1, 0, 2, 1, 2, 3, 4, 2, 3, 1, 2, 0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 4, 2, 6, 6, 7, 0, 1, 3, 0, 1, 3, 3, 2, 4, 3, 4, 4, 2, 5, 5, 7, 8, 3, 5, 0, 2, 0, 3, 3, 0, 2, 1, 3, 0, 1, 1, 1, 3, 2, 1, 3, 1, 6, 3, 1, 2, 3, 3, 4, 5, 5, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 3, 1, 1, 2, 2, 2, 1, 3, 1, 3, 3, 3, 3, 3, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 1, 1, 3, 4, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 2, 3, 3, 4, 2, 3, 5, 1, 2, 1, 1, 3, 3, 3, 5, 3, 5, 3, 2, 1, 3, 2, 3, 2, 3, 4, 3, 2, 3, 5, 1, 3, 5, 5, 8, 0, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 4, 3, 1, 4, 7, 2, 1, 3, 3, 5, 6, 7, 1, 1, 3, 3, 1, 1, 2, 4, 0, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (&yylloc, parm, YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Error token number */ #define YYTERROR 1 #define YYERRCODE 256 /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. If N is 0, then set CURRENT to the empty location which ends the previous symbol: RHS[0] (always defined). */ #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ do \ if (N) \ { \ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ } \ else \ { \ (Current).first_line = (Current).last_line = \ YYRHSLOC (Rhs, 0).last_line; \ (Current).first_column = (Current).last_column = \ YYRHSLOC (Rhs, 0).last_column; \ } \ while (0) #endif #define YYRHSLOC(Rhs, K) ((Rhs)[K]) /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) /* YY_LOCATION_PRINT -- Print the location on the stream. This macro was not mandated originally: define only if we know we won't break user code: when these are the locations we know. */ #ifndef YY_LOCATION_PRINT # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL /* Print *YYLOCP on YYO. Private, do not rely on its existence. */ YY_ATTRIBUTE_UNUSED static unsigned yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp) { unsigned res = 0; int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0; if (0 <= yylocp->first_line) { res += YYFPRINTF (yyo, "%d", yylocp->first_line); if (0 <= yylocp->first_column) res += YYFPRINTF (yyo, ".%d", yylocp->first_column); } if (0 <= yylocp->last_line) { if (yylocp->first_line < yylocp->last_line) { res += YYFPRINTF (yyo, "-%d", yylocp->last_line); if (0 <= end_col) res += YYFPRINTF (yyo, ".%d", end_col); } else if (0 <= end_col && yylocp->first_column < end_col) res += YYFPRINTF (yyo, "-%d", end_col); } return res; } # define YY_LOCATION_PRINT(File, Loc) \ yy_location_print_ (File, &(Loc)) # else # define YY_LOCATION_PRINT(File, Loc) ((void) 0) # endif #endif # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Type, Value, Location, parm); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*----------------------------------------. | Print this symbol's value on YYOUTPUT. | `----------------------------------------*/ static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, void *parm) { FILE *yyo = yyoutput; YYUSE (yyo); YYUSE (yylocationp); YYUSE (parm); if (!yyvaluep) return; # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # endif YYUSE (yytype); } /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, void *parm) { YYFPRINTF (yyoutput, "%s %s (", yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); YY_LOCATION_PRINT (yyoutput, *yylocationp); YYFPRINTF (yyoutput, ": "); yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, parm); YYFPRINTF (yyoutput, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, void *parm) { unsigned long yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yystos[yyssp[yyi + 1 - yynrhs]], &(yyvsp[(yyi + 1) - (yynrhs)]) , &(yylsp[(yyi + 1) - (yynrhs)]) , parm); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, yylsp, Rule, parm); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen strlen # else /* Return the length of YYSTR. */ static YYSIZE_T yystrlen (const char *yystr) { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif # endif # ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ static char * yystpcpy (char *yydest, const char *yysrc) { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif # ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYSIZE_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYSIZE_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; /* Fall through. */ default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (! yyres) return yystrlen (yystr); return yystpcpy (yyres, yystr) - yyres; } # endif /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message about the unexpected token YYTOKEN for the state stack whose top is YYSSP. Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is not large enough to hold the message. In that case, also set *YYMSG_ALLOC to the required number of bytes. Return 2 if the required number of bytes is too large to store. */ static int yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, yytype_int16 *yyssp, int yytoken) { YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); YYSIZE_T yysize = yysize0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ const char *yyformat = YY_NULLPTR; /* Arguments of yyformat. */ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; /* Number of reported tokens (one for the "unexpected", one per "expected"). */ int yycount = 0; /* There are many possibilities here to consider: - If this state is a consistent state with a default action, then the only way this function was invoked is if the default action is an error action. In that case, don't check for expected tokens because there are none. - The only way there can be no lookahead present (in yychar) is if this state is a consistent state with a default action. Thus, detecting the absence of a lookahead is sufficient to determine that there is no unexpected or expected token to report. In that case, just report a simple "syntax error". - Don't assume there isn't a lookahead just because this state is a consistent state with a default action. There might have been a previous inconsistent state, consistent state with a non-default action, or user semantic action that manipulated yychar. - Of course, the expected token list depends on states to have correct lookahead information, and it depends on the parser not to perform extra reductions after fetching a lookahead from the scanner and before detecting a syntax error. Thus, state merging (from LALR or IELR) and default reductions corrupt the expected token list. However, the list is correct for canonical LR with one exception: it will still contain any token that will not be accepted due to an error action in a later state. */ if (yytoken != YYEMPTY) { int yyn = yypact[*yyssp]; yyarg[yycount++] = yytname[yytoken]; if (!yypact_value_is_default (yyn)) { /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. In other words, skip the first -YYN actions for this state because they are default actions. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yyx; for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR && !yytable_value_is_error (yytable[yyx + yyn])) { if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) { yycount = 1; yysize = yysize0; break; } yyarg[yycount++] = yytname[yyx]; { YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; } } } } switch (yycount) { # define YYCASE_(N, S) \ case N: \ yyformat = S; \ break default: /* Avoid compiler warnings. */ YYCASE_(0, YY_("syntax error")); YYCASE_(1, YY_("syntax error, unexpected %s")); YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); # undef YYCASE_ } { YYSIZE_T yysize1 = yysize + yystrlen (yyformat); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; } if (*yymsg_alloc < yysize) { *yymsg_alloc = 2 * yysize; if (! (yysize <= *yymsg_alloc && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; return 1; } /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ { char *yyp = *yymsg; int yyi = 0; while ((*yyp = *yyformat) != '\0') if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yyarg[yyi++]); yyformat += 2; } else { yyp++; yyformat++; } } return 0; } #endif /* YYERROR_VERBOSE */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, void *parm) { YYUSE (yyvaluep); YYUSE (yylocationp); YYUSE (parm); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YYUSE (yytype); YY_IGNORE_MAYBE_UNINITIALIZED_END } /*----------. | yyparse. | `----------*/ int yyparse (void *parm) { /* The lookahead symbol. */ int yychar; /* The semantic value of the lookahead symbol. */ /* Default value used for initialization, for pacifying older GCCs or non-GCC compilers. */ YY_INITIAL_VALUE (static YYSTYPE yyval_default;) YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); /* Location data for the lookahead symbol. */ static YYLTYPE yyloc_default # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL = { 1, 1, 1, 1 } # endif ; YYLTYPE yylloc = yyloc_default; /* Number of syntax errors so far. */ int yynerrs; int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* The stacks and their tools: 'yyss': related to states. 'yyvs': related to semantic values. 'yyls': related to locations. Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ yytype_int16 yyssa[YYINITDEPTH]; yytype_int16 *yyss; yytype_int16 *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs; YYSTYPE *yyvsp; /* The location stack. */ YYLTYPE yylsa[YYINITDEPTH]; YYLTYPE *yyls; YYLTYPE *yylsp; /* The locations where the error started and ended. */ YYLTYPE yyerror_range[3]; YYSIZE_T yystacksize; int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ int yytoken = 0; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; YYLTYPE yyloc; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; yyssp = yyss = yyssa; yyvsp = yyvs = yyvsa; yylsp = yyls = yylsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ /* User initialization code. */ { GCLock lock; yylloc.filename(ASTString(static_cast(parm)->filename)); } yylsp[0] = yylloc; goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; YYLTYPE *yyls1 = yyls; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yyls1, yysize * sizeof (*yylsp), &yystacksize); yyls = yyls1; yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyexhaustedlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yytype_int16 *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); YYSTACK_RELOCATE (yyls_alloc, yyls); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; yylsp = yyls + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = yylex (&yylval, &yylloc, SCANNER); } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); /* Discard the shifted token. */ yychar = YYEMPTY; yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END *++yylsp = yylloc; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; /* Default location. */ YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); yyerror_range[1] = yyloc; YY_REDUCE_PRINT (yyn); switch (yyn) { case 5: { ParserState* pp = static_cast(parm); if ((yyvsp[0].item)) { pp->model->addItem((yyvsp[0].item)); GC::unlock(); GC::lock(); } } break; case 6: { ParserState* pp = static_cast(parm); if ((yyvsp[0].item)) { pp->model->addItem((yyvsp[0].item)); GC::unlock(); GC::lock(); } } break; case 7: { ParserState* pp = static_cast(parm); if ((yyvsp[0].item)) { pp->model->addItem((yyvsp[0].item)); GC::unlock(); GC::lock(); } } break; case 8: { ParserState* pp = static_cast(parm); if ((yyvsp[0].item)) { pp->model->addItem((yyvsp[0].item)); GC::unlock(); GC::lock(); } } break; case 9: { yyerror(&(yylsp[0]), parm, "unexpected item, expecting ';' or end of file"); YYERROR; } break; case 11: { ParserState* pp = static_cast(parm); if (pp->parseDocComments && (yyvsp[0].sValue)) { pp->model->addDocComment((yyvsp[0].sValue)); } free((yyvsp[0].sValue)); } break; case 12: { ParserState* pp = static_cast(parm); if (pp->parseDocComments && (yyvsp[0].sValue)) { pp->model->addDocComment((yyvsp[0].sValue)); } free((yyvsp[0].sValue)); } break; case 15: { (yyval.item) = (yyvsp[0].item); ParserState* pp = static_cast(parm); if (FunctionI* fi = Item::dyn_cast((yyval.item))) { if (pp->parseDocComments) { fi->ann().add(createDocComment((yylsp[-1]),(yyvsp[-1].sValue))); } } else if (VarDeclI* vdi = Item::dyn_cast((yyval.item))) { if (pp->parseDocComments) { vdi->e()->addAnnotation(createDocComment((yylsp[-1]),(yyvsp[-1].sValue))); } } else { yyerror(&(yylsp[0]), parm, "documentation comments are only supported for function, predicate and variable declarations"); } free((yyvsp[-1].sValue)); } break; case 16: { (yyval.item) = (yyvsp[0].item); } break; case 17: { (yyval.item)=notInDatafile(&(yyloc),parm,"include") ? (yyvsp[0].item) : NULL; } break; case 18: { (yyval.item)=notInDatafile(&(yyloc),parm,"variable declaration") ? (yyvsp[0].item) : NULL; } break; case 20: { (yyval.item)=notInDatafile(&(yyloc),parm,"constraint") ? (yyvsp[0].item) : NULL; } break; case 21: { (yyval.item)=notInDatafile(&(yyloc),parm,"solve") ? (yyvsp[0].item) : NULL; } break; case 22: { (yyval.item)=notInDatafile(&(yyloc),parm,"output") ? (yyvsp[0].item) : NULL; } break; case 23: { (yyval.item)=notInDatafile(&(yyloc),parm,"predicate") ? (yyvsp[0].item) : NULL; } break; case 24: { (yyval.item)=notInDatafile(&(yyloc),parm,"predicate") ? (yyvsp[0].item) : NULL; } break; case 25: { (yyval.item)=notInDatafile(&(yyloc),parm,"annotation") ? (yyvsp[0].item) : NULL; } break; case 35: { ParserState* pp = static_cast(parm); map::iterator ret = pp->seenModels.find((yyvsp[0].sValue)); IncludeI* ii = new IncludeI((yyloc),ASTString((yyvsp[0].sValue))); (yyval.item) = ii; if (ret == pp->seenModels.end()) { Model* im = new Model; im->setParent(pp->model); im->setFilename((yyvsp[0].sValue)); string fpath = FileUtils::dir_name(pp->filename); string fbase = FileUtils::base_name(pp->filename); if (fpath=="") fpath="./"; ParseWorkItem pm(im, ii, fpath, (yyvsp[0].sValue)); pp->files.push_back(pm); ii->m(im); pp->seenModels.insert(pair((yyvsp[0].sValue),im)); } else { ii->m(ret->second, false); } free((yyvsp[0].sValue)); } break; case 36: { if ((yyvsp[-1].vardeclexpr) && (yyvsp[0].expression_v)) (yyvsp[-1].vardeclexpr)->addAnnotations(*(yyvsp[0].expression_v)); if ((yyvsp[-1].vardeclexpr)) (yyval.item) = new VarDeclI((yyloc),(yyvsp[-1].vardeclexpr)); delete (yyvsp[0].expression_v); } break; case 37: { if ((yyvsp[-3].vardeclexpr)) (yyvsp[-3].vardeclexpr)->e((yyvsp[0].expression)); if ((yyvsp[-3].vardeclexpr) && (yyvsp[-2].expression_v)) (yyvsp[-3].vardeclexpr)->addAnnotations(*(yyvsp[-2].expression_v)); if ((yyvsp[-3].vardeclexpr)) (yyval.item) = new VarDeclI((yyloc),(yyvsp[-3].vardeclexpr)); delete (yyvsp[-2].expression_v); } break; case 38: { TypeInst* ti = new TypeInst((yyloc),Type::parsetint()); ti->setIsEnum(true); VarDecl* vd = new VarDecl((yyloc),ti,(yyvsp[0].sValue)); free((yyvsp[0].sValue)); (yyval.item) = new VarDeclI((yyloc),vd); } break; case 39: { TypeInst* ti = new TypeInst((yyloc),Type::parsetint()); ti->setIsEnum(true); SetLit* sl = new SetLit((yyloc), *(yyvsp[-1].expression_v)); VarDecl* vd = new VarDecl((yyloc),ti,(yyvsp[-4].sValue),sl); free((yyvsp[-4].sValue)); delete (yyvsp[-1].expression_v); (yyval.item) = new VarDeclI((yyloc),vd); } break; case 40: { TypeInst* ti = new TypeInst((yyloc),Type::parsetint()); ti->setIsEnum(true); vector args; args.push_back(new ArrayLit((yyloc),*(yyvsp[-1].expression_v))); Call* sl = new Call((yyloc), constants().ids.anonEnumFromStrings, args); VarDecl* vd = new VarDecl((yyloc),ti,(yyvsp[-4].sValue),sl); free((yyvsp[-4].sValue)); delete (yyvsp[-1].expression_v); (yyval.item) = new VarDeclI((yyloc),vd); } break; case 41: { TypeInst* ti = new TypeInst((yyloc),Type::parsetint()); ti->setIsEnum(true); vector args; args.push_back((yyvsp[-1].expression)); Call* sl = new Call((yyloc), ASTString((yyvsp[-3].sValue)), args); VarDecl* vd = new VarDecl((yyloc),ti,(yyvsp[-5].sValue),sl); free((yyvsp[-5].sValue)); free((yyvsp[-3].sValue)); (yyval.item) = new VarDeclI((yyloc),vd); } break; case 42: { (yyval.expression_v) = new std::vector(); } break; case 43: { (yyval.expression_v) = new std::vector(); (yyval.expression_v)->push_back(new StringLit((yyloc), (yyvsp[0].sValue))); free((yyvsp[0].sValue)); } break; case 44: { (yyval.expression_v) = (yyvsp[-2].expression_v); if ((yyval.expression_v)) (yyval.expression_v)->push_back(new StringLit((yyloc), (yyvsp[0].sValue))); free((yyvsp[0].sValue)); } break; case 45: { (yyval.expression_v) = new std::vector(); } break; case 46: { (yyval.expression_v) = new std::vector(); (yyval.expression_v)->push_back(new Id((yyloc),(yyvsp[0].sValue),NULL)); free((yyvsp[0].sValue)); } break; case 47: { (yyval.expression_v) = (yyvsp[-2].expression_v); if ((yyval.expression_v)) (yyval.expression_v)->push_back(new Id((yyloc),(yyvsp[0].sValue),NULL)); free((yyvsp[0].sValue)); } break; case 48: { (yyval.item) = new AssignI((yyloc),(yyvsp[-2].sValue),(yyvsp[0].expression)); free((yyvsp[-2].sValue)); } break; case 49: { (yyval.item) = new ConstraintI((yyloc),(yyvsp[0].expression));} break; case 50: { (yyval.item) = new ConstraintI((yyloc),(yyvsp[0].expression)); if ((yyvsp[0].expression) && (yyvsp[-1].expression)) (yyval.item)->cast()->e()->ann().add(new Call((yylsp[-2]), ASTString("mzn_constraint_name"), {(yyvsp[-1].expression)})); } break; case 51: { (yyval.item) = SolveI::sat((yyloc)); if ((yyval.item) && (yyvsp[-1].expression_v)) (yyval.item)->cast()->ann().add(*(yyvsp[-1].expression_v)); delete (yyvsp[-1].expression_v); } break; case 52: { (yyval.item) = SolveI::min((yyloc),(yyvsp[0].expression)); if ((yyval.item) && (yyvsp[-2].expression_v)) (yyval.item)->cast()->ann().add(*(yyvsp[-2].expression_v)); delete (yyvsp[-2].expression_v); } break; case 53: { (yyval.item) = SolveI::max((yyloc),(yyvsp[0].expression)); if ((yyval.item) && (yyvsp[-2].expression_v)) (yyval.item)->cast()->ann().add(*(yyvsp[-2].expression_v)); delete (yyvsp[-2].expression_v); } break; case 54: { (yyval.item) = new OutputI((yyloc),(yyvsp[0].expression));} break; case 55: { if ((yyvsp[-2].vardeclexpr_v)) (yyval.item) = new FunctionI((yyloc),(yyvsp[-3].sValue),new TypeInst((yyloc), Type::varbool()),*(yyvsp[-2].vardeclexpr_v),(yyvsp[0].expression)); if ((yyval.item) && (yyvsp[-1].expression_v)) (yyval.item)->cast()->ann().add(*(yyvsp[-1].expression_v)); free((yyvsp[-3].sValue)); delete (yyvsp[-2].vardeclexpr_v); delete (yyvsp[-1].expression_v); } break; case 56: { if ((yyvsp[-2].vardeclexpr_v)) (yyval.item) = new FunctionI((yyloc),(yyvsp[-3].sValue),new TypeInst((yyloc), Type::parbool()),*(yyvsp[-2].vardeclexpr_v),(yyvsp[0].expression)); if ((yyval.item) && (yyvsp[-1].expression_v)) (yyval.item)->cast()->ann().add(*(yyvsp[-1].expression_v)); free((yyvsp[-3].sValue)); delete (yyvsp[-2].vardeclexpr_v); delete (yyvsp[-1].expression_v); } break; case 57: { if ((yyvsp[-2].vardeclexpr_v)) (yyval.item) = new FunctionI((yyloc),(yyvsp[-3].sValue),(yyvsp[-5].tiexpr),*(yyvsp[-2].vardeclexpr_v),(yyvsp[0].expression)); if ((yyval.item) && (yyvsp[-1].expression_v)) (yyval.item)->cast()->ann().add(*(yyvsp[-1].expression_v)); free((yyvsp[-3].sValue)); delete (yyvsp[-2].vardeclexpr_v); delete (yyvsp[-1].expression_v); } break; case 58: { if ((yyvsp[-3].vardeclexpr_v)) (yyval.item) = new FunctionI((yyloc),(yyvsp[-5].sValue),(yyvsp[-7].tiexpr),*(yyvsp[-3].vardeclexpr_v),(yyvsp[0].expression)); if ((yyval.item) && (yyvsp[-1].expression_v)) (yyval.item)->cast()->ann().add(*(yyvsp[-1].expression_v)); free((yyvsp[-5].sValue)); delete (yyvsp[-3].vardeclexpr_v); delete (yyvsp[-1].expression_v); } break; case 59: { TypeInst* ti=new TypeInst((yylsp[-2]),Type::ann()); if ((yyvsp[0].vardeclexpr_v)==NULL || (yyvsp[0].vardeclexpr_v)->empty()) { VarDecl* vd = new VarDecl((yyloc),ti,(yyvsp[-1].sValue)); (yyval.item) = new VarDeclI((yyloc),vd); } else { (yyval.item) = new FunctionI((yyloc),(yyvsp[-1].sValue),ti,*(yyvsp[0].vardeclexpr_v),NULL); } free((yyvsp[-1].sValue)); delete (yyvsp[0].vardeclexpr_v); } break; case 60: { TypeInst* ti=new TypeInst((yylsp[-4]),Type::ann()); if ((yyvsp[-2].vardeclexpr_v)) (yyval.item) = new FunctionI((yyloc),(yyvsp[-3].sValue),ti,*(yyvsp[-2].vardeclexpr_v),(yyvsp[0].expression)); delete (yyvsp[-2].vardeclexpr_v); } break; case 61: { (yyval.expression)=NULL; } break; case 62: { (yyval.expression)=(yyvsp[0].expression); } break; case 63: { (yyval.vardeclexpr_v)=new vector(); } break; case 64: { (yyval.vardeclexpr_v)=(yyvsp[-1].vardeclexpr_v); } break; case 65: { (yyval.vardeclexpr_v)=new vector(); } break; case 66: { (yyval.vardeclexpr_v)=new vector(); } break; case 67: { (yyval.vardeclexpr_v)=(yyvsp[-1].vardeclexpr_v); } break; case 68: { (yyval.vardeclexpr_v)=new vector(); if ((yyvsp[0].vardeclexpr)) (yyvsp[0].vardeclexpr)->toplevel(false); if ((yyvsp[0].vardeclexpr)) (yyval.vardeclexpr_v)->push_back((yyvsp[0].vardeclexpr)); } break; case 69: { (yyval.vardeclexpr_v)=(yyvsp[-2].vardeclexpr_v); if ((yyvsp[0].vardeclexpr)) (yyvsp[0].vardeclexpr)->toplevel(false); if ((yyvsp[-2].vardeclexpr_v) && (yyvsp[0].vardeclexpr)) (yyvsp[-2].vardeclexpr_v)->push_back((yyvsp[0].vardeclexpr)); } break; case 72: { (yyval.vardeclexpr)=(yyvsp[0].vardeclexpr); } break; case 73: { if ((yyvsp[0].tiexpr)) (yyval.vardeclexpr)=new VarDecl((yyloc), (yyvsp[0].tiexpr), ""); } break; case 74: { if ((yyvsp[-2].tiexpr) && (yyvsp[0].sValue)) (yyval.vardeclexpr) = new VarDecl((yyloc), (yyvsp[-2].tiexpr), (yyvsp[0].sValue)); free((yyvsp[0].sValue)); } break; case 75: { (yyval.tiexpr_v)=(yyvsp[-1].tiexpr_v); } break; case 76: { (yyval.tiexpr_v)=new vector(); (yyval.tiexpr_v)->push_back((yyvsp[0].tiexpr)); } break; case 77: { (yyval.tiexpr_v)=(yyvsp[-2].tiexpr_v); if ((yyvsp[-2].tiexpr_v) && (yyvsp[0].tiexpr)) (yyvsp[-2].tiexpr_v)->push_back((yyvsp[0].tiexpr)); } break; case 79: { (yyval.tiexpr) = (yyvsp[0].tiexpr); if ((yyval.tiexpr) && (yyvsp[-3].tiexpr_v)) (yyval.tiexpr)->setRanges(*(yyvsp[-3].tiexpr_v)); delete (yyvsp[-3].tiexpr_v); } break; case 80: { (yyval.tiexpr) = (yyvsp[0].tiexpr); std::vector ti(1); ti[0] = new TypeInst((yyloc),Type::parint()); if ((yyval.tiexpr)) (yyval.tiexpr)->setRanges(ti); } break; case 81: { (yyval.tiexpr) = (yyvsp[0].tiexpr); } break; case 82: { (yyval.tiexpr) = (yyvsp[0].tiexpr); if ((yyval.tiexpr)) { Type tt = (yyval.tiexpr)->type(); tt.ot(Type::OT_OPTIONAL); (yyval.tiexpr)->type(tt); } } break; case 83: { (yyval.tiexpr) = (yyvsp[0].tiexpr); if ((yyval.tiexpr) && (yyvsp[-1].bValue)) { Type tt = (yyval.tiexpr)->type(); tt.ot(Type::OT_OPTIONAL); (yyval.tiexpr)->type(tt); } } break; case 84: { (yyval.tiexpr) = (yyvsp[0].tiexpr); if ((yyval.tiexpr)) { Type tt = (yyval.tiexpr)->type(); tt.ti(Type::TI_VAR); if ((yyvsp[-1].bValue)) tt.ot(Type::OT_OPTIONAL); (yyval.tiexpr)->type(tt); } } break; case 85: { (yyval.tiexpr) = (yyvsp[0].tiexpr); if ((yyval.tiexpr)) { Type tt = (yyval.tiexpr)->type(); tt.st(Type::ST_SET); if ((yyvsp[-3].bValue)) tt.ot(Type::OT_OPTIONAL); (yyval.tiexpr)->type(tt); } } break; case 86: { (yyval.tiexpr) = (yyvsp[0].tiexpr); if ((yyval.tiexpr)) { Type tt = (yyval.tiexpr)->type(); tt.st(Type::ST_SET); if ((yyvsp[-3].bValue)) tt.ot(Type::OT_OPTIONAL); (yyval.tiexpr)->type(tt); } } break; case 87: { (yyval.tiexpr) = (yyvsp[0].tiexpr); if ((yyval.tiexpr)) { Type tt = (yyval.tiexpr)->type(); tt.ti(Type::TI_VAR); tt.st(Type::ST_SET); if ((yyvsp[-3].bValue)) tt.ot(Type::OT_OPTIONAL); (yyval.tiexpr)->type(tt); } } break; case 88: { (yyval.bValue) = false; } break; case 89: { (yyval.bValue) = true; } break; case 90: { (yyval.tiexpr) = new TypeInst((yyloc),Type::parint()); } break; case 91: { (yyval.tiexpr) = new TypeInst((yyloc),Type::parbool()); } break; case 92: { (yyval.tiexpr) = new TypeInst((yyloc),Type::parfloat()); } break; case 93: { (yyval.tiexpr) = new TypeInst((yyloc),Type::parstring()); } break; case 94: { (yyval.tiexpr) = new TypeInst((yyloc),Type::ann()); } break; case 95: { if ((yyvsp[0].expression)) (yyval.tiexpr) = new TypeInst((yyloc),Type(),(yyvsp[0].expression)); } break; case 96: { (yyval.tiexpr) = new TypeInst((yyloc),Type::top(), new TIId((yyloc), (yyvsp[0].sValue))); free((yyvsp[0].sValue)); } break; case 97: { (yyval.tiexpr) = new TypeInst((yyloc),Type::parint(), new TIId((yyloc), (yyvsp[0].sValue))); free((yyvsp[0].sValue)); } break; case 99: { (yyval.expression_v)=new std::vector; (yyval.expression_v)->push_back((yyvsp[0].expression)); } break; case 100: { (yyval.expression_v)=(yyvsp[-2].expression_v); if ((yyval.expression_v) && (yyvsp[0].expression)) (yyval.expression_v)->push_back((yyvsp[0].expression)); } break; case 101: { (yyval.expression) = (yyvsp[0].expression); } break; case 102: { (yyval.expression)=new SetLit((yyloc), IntSetVal::a(-IntVal::infinity(),IntVal::infinity())); } break; case 103: { if ((yyvsp[0].expression)==NULL) { (yyval.expression) = NULL; } else if ((yyvsp[0].expression)->isa()) { (yyval.expression)=new SetLit((yyloc), IntSetVal::a(-IntVal::infinity(),(yyvsp[0].expression)->cast()->v())); } else { (yyval.expression)=new BinOp((yyloc), IntLit::a(-IntVal::infinity()), BOT_DOTDOT, (yyvsp[0].expression)); } } break; case 104: { if ((yyvsp[-1].expression)==NULL) { (yyval.expression) = NULL; } else if ((yyvsp[-1].expression)->isa()) { (yyval.expression)=new SetLit((yyloc), IntSetVal::a((yyvsp[-1].expression)->cast()->v(),IntVal::infinity())); } else { (yyval.expression)=new BinOp((yyloc), (yyvsp[-1].expression), BOT_DOTDOT, IntLit::a(IntVal::infinity())); } } break; case 106: { (yyval.expression_v)=new std::vector; (yyval.expression_v)->push_back((yyvsp[0].expression)); } break; case 107: { (yyval.expression_v)=(yyvsp[-2].expression_v); if ((yyval.expression_v) && (yyvsp[0].expression)) (yyval.expression_v)->push_back((yyvsp[0].expression)); } break; case 109: { if ((yyvsp[-2].expression) && (yyvsp[0].expression)) (yyvsp[-2].expression)->addAnnotation((yyvsp[0].expression)); (yyval.expression)=(yyvsp[-2].expression); } break; case 110: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_UNION, (yyvsp[0].expression)); } break; case 111: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_DIFF, (yyvsp[0].expression)); } break; case 112: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_SYMDIFF, (yyvsp[0].expression)); } break; case 113: { if ((yyvsp[-2].expression)==NULL || (yyvsp[0].expression)==NULL) { (yyval.expression) = NULL; } else if ((yyvsp[-2].expression)->isa() && (yyvsp[0].expression)->isa()) { (yyval.expression)=new SetLit((yyloc), IntSetVal::a((yyvsp[-2].expression)->cast()->v(),(yyvsp[0].expression)->cast()->v())); } else { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_DOTDOT, (yyvsp[0].expression)); } } break; case 114: { if ((yyvsp[-3].expression)==NULL || (yyvsp[-1].expression)==NULL) { (yyval.expression) = NULL; } else if ((yyvsp[-3].expression)->isa() && (yyvsp[-1].expression)->isa()) { (yyval.expression)=new SetLit((yyloc), IntSetVal::a((yyvsp[-3].expression)->cast()->v(),(yyvsp[-1].expression)->cast()->v())); } else { (yyval.expression)=new BinOp((yyloc), (yyvsp[-3].expression), BOT_DOTDOT, (yyvsp[-1].expression)); } } break; case 115: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_INTERSECT, (yyvsp[0].expression)); } break; case 116: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_PLUSPLUS, (yyvsp[0].expression)); } break; case 117: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_PLUS, (yyvsp[0].expression)); } break; case 118: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_MINUS, (yyvsp[0].expression)); } break; case 119: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_MULT, (yyvsp[0].expression)); } break; case 120: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_DIV, (yyvsp[0].expression)); } break; case 121: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_IDIV, (yyvsp[0].expression)); } break; case 122: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_MOD, (yyvsp[0].expression)); } break; case 123: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_POW, (yyvsp[0].expression)); } break; case 124: { vector args; args.push_back((yyvsp[-2].expression)); args.push_back((yyvsp[0].expression)); (yyval.expression)=new Call((yyloc), ASTString("~+"), args); } break; case 125: { vector args; args.push_back((yyvsp[-2].expression)); args.push_back((yyvsp[0].expression)); (yyval.expression)=new Call((yyloc), ASTString("~-"), args); } break; case 126: { vector args; args.push_back((yyvsp[-2].expression)); args.push_back((yyvsp[0].expression)); (yyval.expression)=new Call((yyloc), ASTString("~*"), args); } break; case 127: { vector args; args.push_back((yyvsp[-2].expression)); args.push_back((yyvsp[0].expression)); (yyval.expression)=new Call((yyloc), ASTString("~="), args); } break; case 128: { vector args; args.push_back((yyvsp[-2].expression)); args.push_back((yyvsp[0].expression)); (yyval.expression)=new Call((yyloc), (yyvsp[-1].sValue), args); free((yyvsp[-1].sValue)); } break; case 129: { (yyval.expression)=new UnOp((yyloc), UOT_PLUS, (yyvsp[0].expression)); } break; case 130: { if ((yyvsp[0].expression) && (yyvsp[0].expression)->isa()) { (yyval.expression) = IntLit::a(-(yyvsp[0].expression)->cast()->v()); } else if ((yyvsp[0].expression) && (yyvsp[0].expression)->isa()) { (yyval.expression) = FloatLit::a(-(yyvsp[0].expression)->cast()->v()); } else { (yyval.expression)=new UnOp((yyloc), UOT_MINUS, (yyvsp[0].expression)); } } break; case 132: { if ((yyvsp[-2].expression) && (yyvsp[0].expression)) (yyvsp[-2].expression)->addAnnotation((yyvsp[0].expression)); (yyval.expression)=(yyvsp[-2].expression); } break; case 133: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_EQUIV, (yyvsp[0].expression)); } break; case 134: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_IMPL, (yyvsp[0].expression)); } break; case 135: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_RIMPL, (yyvsp[0].expression)); } break; case 136: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_OR, (yyvsp[0].expression)); } break; case 137: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_XOR, (yyvsp[0].expression)); } break; case 138: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_AND, (yyvsp[0].expression)); } break; case 139: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_LE, (yyvsp[0].expression)); } break; case 140: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_GR, (yyvsp[0].expression)); } break; case 141: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_LQ, (yyvsp[0].expression)); } break; case 142: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_GQ, (yyvsp[0].expression)); } break; case 143: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_EQ, (yyvsp[0].expression)); } break; case 144: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_NQ, (yyvsp[0].expression)); } break; case 145: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_IN, (yyvsp[0].expression)); } break; case 146: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_SUBSET, (yyvsp[0].expression)); } break; case 147: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_SUPERSET, (yyvsp[0].expression)); } break; case 148: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_UNION, (yyvsp[0].expression)); } break; case 149: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_DIFF, (yyvsp[0].expression)); } break; case 150: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_SYMDIFF, (yyvsp[0].expression)); } break; case 151: { if ((yyvsp[-2].expression)==NULL || (yyvsp[0].expression)==NULL) { (yyval.expression) = NULL; } else if ((yyvsp[-2].expression)->isa() && (yyvsp[0].expression)->isa()) { (yyval.expression)=new SetLit((yyloc), IntSetVal::a((yyvsp[-2].expression)->cast()->v(),(yyvsp[0].expression)->cast()->v())); } else { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_DOTDOT, (yyvsp[0].expression)); } } break; case 152: { if ((yyvsp[-3].expression)==NULL || (yyvsp[-1].expression)==NULL) { (yyval.expression) = NULL; } else if ((yyvsp[-3].expression)->isa() && (yyvsp[-1].expression)->isa()) { (yyval.expression)=new SetLit((yyloc), IntSetVal::a((yyvsp[-3].expression)->cast()->v(),(yyvsp[-1].expression)->cast()->v())); } else { (yyval.expression)=new BinOp((yyloc), (yyvsp[-3].expression), BOT_DOTDOT, (yyvsp[-1].expression)); } } break; case 153: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_INTERSECT, (yyvsp[0].expression)); } break; case 154: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_PLUSPLUS, (yyvsp[0].expression)); } break; case 155: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_PLUS, (yyvsp[0].expression)); } break; case 156: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_MINUS, (yyvsp[0].expression)); } break; case 157: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_MULT, (yyvsp[0].expression)); } break; case 158: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_DIV, (yyvsp[0].expression)); } break; case 159: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_IDIV, (yyvsp[0].expression)); } break; case 160: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_MOD, (yyvsp[0].expression)); } break; case 161: { (yyval.expression)=new BinOp((yyloc), (yyvsp[-2].expression), BOT_POW, (yyvsp[0].expression)); } break; case 162: { vector args; args.push_back((yyvsp[-2].expression)); args.push_back((yyvsp[0].expression)); (yyval.expression)=new Call((yyloc), ASTString("~+"), args); } break; case 163: { vector args; args.push_back((yyvsp[-2].expression)); args.push_back((yyvsp[0].expression)); (yyval.expression)=new Call((yyloc), ASTString("~-"), args); } break; case 164: { vector args; args.push_back((yyvsp[-2].expression)); args.push_back((yyvsp[0].expression)); (yyval.expression)=new Call((yyloc), ASTString("~*"), args); } break; case 165: { vector args; args.push_back((yyvsp[-2].expression)); args.push_back((yyvsp[0].expression)); (yyval.expression)=new Call((yyloc), ASTString("~="), args); } break; case 166: { vector args; args.push_back((yyvsp[-2].expression)); args.push_back((yyvsp[0].expression)); (yyval.expression)=new Call((yyloc), (yyvsp[-1].sValue), args); free((yyvsp[-1].sValue)); } break; case 167: { (yyval.expression)=new UnOp((yyloc), UOT_NOT, (yyvsp[0].expression)); } break; case 168: { if (((yyvsp[0].expression) && (yyvsp[0].expression)->isa()) || ((yyvsp[0].expression) && (yyvsp[0].expression)->isa())) { (yyval.expression) = (yyvsp[0].expression); } else { (yyval.expression)=new UnOp((yyloc), UOT_PLUS, (yyvsp[0].expression)); } } break; case 169: { if ((yyvsp[0].expression) && (yyvsp[0].expression)->isa()) { (yyval.expression) = IntLit::a(-(yyvsp[0].expression)->cast()->v()); } else if ((yyvsp[0].expression) && (yyvsp[0].expression)->isa()) { (yyval.expression) = FloatLit::a(-(yyvsp[0].expression)->cast()->v()); } else { (yyval.expression)=new UnOp((yyloc), UOT_MINUS, (yyvsp[0].expression)); } } break; case 170: { (yyval.expression)=(yyvsp[0].expression); } break; case 171: { (yyval.expression)=(yyvsp[0].expression); } break; case 172: { (yyval.expression)=(yyvsp[-1].expression); } break; case 173: { if ((yyvsp[0].expression_vv)) (yyval.expression)=createArrayAccess((yyloc), (yyvsp[-2].expression), *(yyvsp[0].expression_vv)); delete (yyvsp[0].expression_vv); } break; case 174: { (yyval.expression)=new Id((yyloc), (yyvsp[0].sValue), NULL); free((yyvsp[0].sValue)); } break; case 175: { if ((yyvsp[0].expression_vv)) (yyval.expression)=createArrayAccess((yyloc), new Id((yylsp[-1]),(yyvsp[-1].sValue),NULL), *(yyvsp[0].expression_vv)); free((yyvsp[-1].sValue)); delete (yyvsp[0].expression_vv); } break; case 176: { (yyval.expression)=new AnonVar((yyloc)); } break; case 177: { if ((yyvsp[0].expression_vv)) (yyval.expression)=createArrayAccess((yyloc), new AnonVar((yyloc)), *(yyvsp[0].expression_vv)); delete (yyvsp[0].expression_vv); } break; case 178: { (yyval.expression)=constants().boollit(((yyvsp[0].iValue)!=0)); } break; case 179: { (yyval.expression)=IntLit::a((yyvsp[0].iValue)); } break; case 180: { (yyval.expression)=IntLit::a(IntVal::infinity()); } break; case 181: { (yyval.expression)=FloatLit::a((yyvsp[0].dValue)); } break; case 182: { (yyval.expression)=constants().absent; } break; case 184: { if ((yyvsp[0].expression_vv)) (yyval.expression)=createArrayAccess((yyloc), (yyvsp[-1].expression), *(yyvsp[0].expression_vv)); delete (yyvsp[0].expression_vv); } break; case 186: { if ((yyvsp[0].expression_vv)) (yyval.expression)=createArrayAccess((yyloc), (yyvsp[-1].expression), *(yyvsp[0].expression_vv)); delete (yyvsp[0].expression_vv); } break; case 188: { if ((yyvsp[0].expression_vv)) (yyval.expression)=createArrayAccess((yyloc), (yyvsp[-1].expression), *(yyvsp[0].expression_vv)); delete (yyvsp[0].expression_vv); } break; case 190: { if ((yyvsp[0].expression_vv)) (yyval.expression)=createArrayAccess((yyloc), (yyvsp[-1].expression), *(yyvsp[0].expression_vv)); delete (yyvsp[0].expression_vv); } break; case 192: { if ((yyvsp[0].expression_vv)) (yyval.expression)=createArrayAccess((yyloc), (yyvsp[-1].expression), *(yyvsp[0].expression_vv)); delete (yyvsp[0].expression_vv); } break; case 194: { if ((yyvsp[0].expression_vv)) (yyval.expression)=createArrayAccess((yyloc), (yyvsp[-1].expression), *(yyvsp[0].expression_vv)); delete (yyvsp[0].expression_vv); } break; case 197: { if ((yyvsp[0].expression_vv)) (yyval.expression)=createArrayAccess((yyloc), (yyvsp[-1].expression), *(yyvsp[0].expression_vv)); delete (yyvsp[0].expression_vv); } break; case 198: { (yyval.expression)=new StringLit((yyloc), (yyvsp[0].sValue)); free((yyvsp[0].sValue)); } break; case 199: { (yyval.expression)=new BinOp((yyloc), new StringLit((yyloc), (yyvsp[-1].sValue)), BOT_PLUSPLUS, (yyvsp[0].expression)); free((yyvsp[-1].sValue)); } break; case 200: { if ((yyvsp[-1].expression_v)) (yyval.expression)=new BinOp((yyloc), new Call((yyloc), ASTString("format"), *(yyvsp[-1].expression_v)), BOT_PLUSPLUS, new StringLit((yyloc),(yyvsp[0].sValue))); free((yyvsp[0].sValue)); delete (yyvsp[-1].expression_v); } break; case 201: { if ((yyvsp[-2].expression_v)) (yyval.expression)=new BinOp((yyloc), new Call((yyloc), ASTString("format"), *(yyvsp[-2].expression_v)), BOT_PLUSPLUS, new BinOp((yyloc), new StringLit((yyloc),(yyvsp[-1].sValue)), BOT_PLUSPLUS, (yyvsp[0].expression))); free((yyvsp[-1].sValue)); delete (yyvsp[-2].expression_v); } break; case 202: { (yyval.expression_vv)=new std::vector >(); if ((yyvsp[-1].expression_v)) { (yyval.expression_vv)->push_back(*(yyvsp[-1].expression_v)); delete (yyvsp[-1].expression_v); } } break; case 203: { (yyval.expression_vv)=(yyvsp[-3].expression_vv); if ((yyval.expression_vv) && (yyvsp[-1].expression_v)) { (yyval.expression_vv)->push_back(*(yyvsp[-1].expression_v)); delete (yyvsp[-1].expression_v); } } break; case 204: { (yyval.expression) = new SetLit((yyloc), std::vector()); } break; case 205: { if ((yyvsp[-1].expression_v)) (yyval.expression) = new SetLit((yyloc), *(yyvsp[-1].expression_v)); delete (yyvsp[-1].expression_v); } break; case 206: { if ((yyvsp[-1].generators)) (yyval.expression) = new Comprehension((yyloc), (yyvsp[-3].expression), *(yyvsp[-1].generators), true); delete (yyvsp[-1].generators); } break; case 207: { if ((yyvsp[0].generator_v)) (yyval.generators)=new Generators; (yyval.generators)->_g = *(yyvsp[0].generator_v); delete (yyvsp[0].generator_v); } break; case 209: { (yyval.generator_v)=new std::vector; if ((yyvsp[0].generator)) (yyval.generator_v)->push_back(*(yyvsp[0].generator)); delete (yyvsp[0].generator); } break; case 210: { (yyval.generator_v)=new std::vector; if ((yyvsp[0].generator)) (yyval.generator_v)->push_back(*(yyvsp[0].generator)); delete (yyvsp[0].generator); } break; case 211: { (yyval.generator_v)=new std::vector; if ((yyvsp[-2].generator)) (yyval.generator_v)->push_back(*(yyvsp[-2].generator)); if ((yyvsp[-2].generator) && (yyvsp[0].expression)) (yyval.generator_v)->push_back(Generator((yyval.generator_v)->size(),(yyvsp[0].expression))); delete (yyvsp[-2].generator); } break; case 212: { (yyval.generator_v)=(yyvsp[-2].generator_v); if ((yyval.generator_v) && (yyvsp[0].generator)) (yyval.generator_v)->push_back(*(yyvsp[0].generator)); delete (yyvsp[0].generator); } break; case 213: { (yyval.generator_v)=(yyvsp[-2].generator_v); if ((yyval.generator_v) && (yyvsp[0].generator)) (yyval.generator_v)->push_back(*(yyvsp[0].generator)); delete (yyvsp[0].generator); } break; case 214: { (yyval.generator_v)=(yyvsp[-4].generator_v); if ((yyval.generator_v) && (yyvsp[-2].generator)) (yyval.generator_v)->push_back(*(yyvsp[-2].generator)); if ((yyval.generator_v) && (yyvsp[-2].generator) && (yyvsp[0].expression)) (yyval.generator_v)->push_back(Generator((yyval.generator_v)->size(),(yyvsp[0].expression))); delete (yyvsp[-2].generator); } break; case 215: { if ((yyvsp[-2].string_v) && (yyvsp[0].expression)) (yyval.generator)=new Generator(*(yyvsp[-2].string_v),(yyvsp[0].expression),NULL); else (yyval.generator)=NULL; delete (yyvsp[-2].string_v); } break; case 216: { if ((yyvsp[-4].string_v) && (yyvsp[-2].expression)) (yyval.generator)=new Generator(*(yyvsp[-4].string_v),(yyvsp[-2].expression),(yyvsp[0].expression)); else (yyval.generator)=NULL; delete (yyvsp[-4].string_v); } break; case 217: { if ((yyvsp[0].expression)) (yyval.generator)=new Generator({(yyvsp[-2].sValue)},NULL,(yyvsp[0].expression)); else (yyval.generator)=NULL; free((yyvsp[-2].sValue)); } break; case 219: { (yyval.string_v)=new std::vector; (yyval.string_v)->push_back((yyvsp[0].sValue)); free((yyvsp[0].sValue)); } break; case 220: { (yyval.string_v)=(yyvsp[-2].string_v); if ((yyval.string_v) && (yyvsp[0].sValue)) (yyval.string_v)->push_back((yyvsp[0].sValue)); free((yyvsp[0].sValue)); } break; case 221: { (yyval.expression)=new ArrayLit((yyloc), std::vector()); } break; case 222: { if ((yyvsp[-1].expression_v)) (yyval.expression)=new ArrayLit((yyloc), *(yyvsp[-1].expression_v)); delete (yyvsp[-1].expression_v); } break; case 223: { (yyval.expression)=new ArrayLit((yyloc), std::vector >()); } break; case 224: { if ((yyvsp[-1].expression_vv)) { (yyval.expression)=new ArrayLit((yyloc), *(yyvsp[-1].expression_vv)); for (unsigned int i=1; i<(yyvsp[-1].expression_vv)->size(); i++) if ((*(yyvsp[-1].expression_vv))[i].size() != (*(yyvsp[-1].expression_vv))[i-1].size()) yyerror(&(yylsp[-1]), parm, "syntax error, all sub-arrays of 2d array literal must have the same length"); delete (yyvsp[-1].expression_vv); } else { (yyval.expression) = NULL; } } break; case 225: { if ((yyvsp[-2].expression_vv)) { (yyval.expression)=new ArrayLit((yyloc), *(yyvsp[-2].expression_vv)); for (unsigned int i=1; i<(yyvsp[-2].expression_vv)->size(); i++) if ((*(yyvsp[-2].expression_vv))[i].size() != (*(yyvsp[-2].expression_vv))[i-1].size()) yyerror(&(yylsp[-2]), parm, "syntax error, all sub-arrays of 2d array literal must have the same length"); delete (yyvsp[-2].expression_vv); } else { (yyval.expression) = NULL; } } break; case 226: { if ((yyvsp[-1].expression_vvv)) { std::vector > dims(3); dims[0] = std::pair(1,static_cast((yyvsp[-1].expression_vvv)->size())); if ((yyvsp[-1].expression_vvv)->size()==0) { dims[1] = std::pair(1,0); dims[2] = std::pair(1,0); } else { dims[1] = std::pair(1,static_cast((*(yyvsp[-1].expression_vvv))[0].size())); if ((*(yyvsp[-1].expression_vvv))[0].size()==0) { dims[2] = std::pair(1,0); } else { dims[2] = std::pair(1,static_cast((*(yyvsp[-1].expression_vvv))[0][0].size())); } } std::vector a; for (int i=0; i > >; } break; case 228: { (yyval.expression_vvv)=new std::vector > >; if ((yyvsp[-1].expression_vv)) (yyval.expression_vvv)->push_back(*(yyvsp[-1].expression_vv)); delete (yyvsp[-1].expression_vv); } break; case 229: { (yyval.expression_vvv)=(yyvsp[-4].expression_vvv); if ((yyval.expression_vvv) && (yyvsp[-1].expression_vv)) (yyval.expression_vvv)->push_back(*(yyvsp[-1].expression_vv)); delete (yyvsp[-1].expression_vv); } break; case 230: { (yyval.expression_vv)=new std::vector >; if ((yyvsp[0].expression_v)) (yyval.expression_vv)->push_back(*(yyvsp[0].expression_v)); delete (yyvsp[0].expression_v); } break; case 231: { (yyval.expression_vv)=(yyvsp[-2].expression_vv); if ((yyval.expression_vv) && (yyvsp[0].expression_v)) (yyval.expression_vv)->push_back(*(yyvsp[0].expression_v)); delete (yyvsp[0].expression_v); } break; case 232: { if ((yyvsp[-1].generators)) (yyval.expression)=new Comprehension((yyloc), (yyvsp[-3].expression), *(yyvsp[-1].generators), false); delete (yyvsp[-1].generators); } break; case 233: { std::vector iexps; iexps.push_back((yyvsp[-3].expression)); iexps.push_back((yyvsp[-1].expression)); (yyval.expression)=new ITE((yyloc), iexps, NULL); } break; case 234: { std::vector iexps; iexps.push_back((yyvsp[-6].expression)); iexps.push_back((yyvsp[-4].expression)); if ((yyvsp[-3].expression_v)) { for (unsigned int i=0; i<(yyvsp[-3].expression_v)->size(); i+=2) { iexps.push_back((*(yyvsp[-3].expression_v))[i]); iexps.push_back((*(yyvsp[-3].expression_v))[i+1]); } } (yyval.expression)=new ITE((yyloc), iexps,(yyvsp[-1].expression)); delete (yyvsp[-3].expression_v); } break; case 235: { (yyval.expression_v)=new std::vector; } break; case 236: { (yyval.expression_v)=(yyvsp[-4].expression_v); if ((yyval.expression_v) && (yyvsp[-2].expression) && (yyvsp[0].expression)) { (yyval.expression_v)->push_back((yyvsp[-2].expression)); (yyval.expression_v)->push_back((yyvsp[0].expression)); } } break; case 237: { (yyval.iValue)=BOT_EQUIV; } break; case 238: { (yyval.iValue)=BOT_IMPL; } break; case 239: { (yyval.iValue)=BOT_RIMPL; } break; case 240: { (yyval.iValue)=BOT_OR; } break; case 241: { (yyval.iValue)=BOT_XOR; } break; case 242: { (yyval.iValue)=BOT_AND; } break; case 243: { (yyval.iValue)=BOT_LE; } break; case 244: { (yyval.iValue)=BOT_GR; } break; case 245: { (yyval.iValue)=BOT_LQ; } break; case 246: { (yyval.iValue)=BOT_GQ; } break; case 247: { (yyval.iValue)=BOT_EQ; } break; case 248: { (yyval.iValue)=BOT_NQ; } break; case 249: { (yyval.iValue)=BOT_IN; } break; case 250: { (yyval.iValue)=BOT_SUBSET; } break; case 251: { (yyval.iValue)=BOT_SUPERSET; } break; case 252: { (yyval.iValue)=BOT_UNION; } break; case 253: { (yyval.iValue)=BOT_DIFF; } break; case 254: { (yyval.iValue)=BOT_SYMDIFF; } break; case 255: { (yyval.iValue)=BOT_PLUS; } break; case 256: { (yyval.iValue)=BOT_MINUS; } break; case 257: { (yyval.iValue)=BOT_MULT; } break; case 258: { (yyval.iValue)=BOT_POW; } break; case 259: { (yyval.iValue)=BOT_DIV; } break; case 260: { (yyval.iValue)=BOT_IDIV; } break; case 261: { (yyval.iValue)=BOT_MOD; } break; case 262: { (yyval.iValue)=BOT_INTERSECT; } break; case 263: { (yyval.iValue)=BOT_PLUSPLUS; } break; case 264: { (yyval.iValue)=-1; } break; case 265: { if ((yyvsp[-5].iValue)==-1) { (yyval.expression)=NULL; yyerror(&(yylsp[-3]), parm, "syntax error, unary operator with two arguments"); } else { (yyval.expression)=new BinOp((yyloc), (yyvsp[-3].expression),static_cast((yyvsp[-5].iValue)),(yyvsp[-1].expression)); } } break; case 266: { int uot=-1; switch ((yyvsp[-3].iValue)) { case -1: uot = UOT_NOT; break; case BOT_MINUS: uot = UOT_MINUS; break; case BOT_PLUS: uot = UOT_PLUS; break; default: yyerror(&(yylsp[-1]), parm, "syntax error, binary operator with unary argument list"); break; } if (uot==-1) (yyval.expression)=NULL; else { if (uot==UOT_PLUS && (yyvsp[-1].expression) && ((yyvsp[-1].expression)->isa() || (yyvsp[-1].expression)->isa())) { (yyval.expression) = (yyvsp[-1].expression); } else if (uot==UOT_MINUS && (yyvsp[-1].expression) && (yyvsp[-1].expression)->isa()) { (yyval.expression) = IntLit::a(-(yyvsp[-1].expression)->cast()->v()); } else if (uot==UOT_MINUS && (yyvsp[-1].expression) && (yyvsp[-1].expression)->isa()) { (yyval.expression) = FloatLit::a(-(yyvsp[-1].expression)->cast()->v()); } else { (yyval.expression)=new UnOp((yyloc), static_cast(uot),(yyvsp[-1].expression)); } } } break; case 267: { (yyval.expression)=new Call((yyloc), (yyvsp[-2].sValue), std::vector()); free((yyvsp[-2].sValue)); } break; case 269: { if ((yyvsp[-1].expression_p)!=NULL) { bool hadWhere = false; std::vector args; for (unsigned int i=0; i<(yyvsp[-1].expression_p)->size(); i++) { if ((*(yyvsp[-1].expression_p))[i].second) { yyerror(&(yylsp[-1]), parm, "syntax error, 'where' expression outside generator call"); hadWhere = true; (yyval.expression)=NULL; } args.push_back((*(yyvsp[-1].expression_p))[i].first); } if (!hadWhere) { (yyval.expression)=new Call((yyloc), (yyvsp[-3].sValue), args); } } free((yyvsp[-3].sValue)); delete (yyvsp[-1].expression_p); } break; case 270: { vector gens; vector ids; if ((yyvsp[-4].expression_p)) { for (unsigned int i=0; i<(yyvsp[-4].expression_p)->size(); i++) { if (Id* id = Expression::dyn_cast((*(yyvsp[-4].expression_p))[i].first)) { if ((*(yyvsp[-4].expression_p))[i].second) { ParserLocation loc = (*(yyvsp[-4].expression_p))[i].second->loc().parserLocation(); yyerror(&loc, parm, "illegal where expression in generator call"); } ids.push_back(id); } else { if (BinOp* boe = Expression::dyn_cast((*(yyvsp[-4].expression_p))[i].first)) { if (boe->lhs() && boe->rhs()) { Id* id = Expression::dyn_cast(boe->lhs()); if (id && boe->op() == BOT_IN) { ids.push_back(id); gens.push_back(Generator(ids,boe->rhs(),(*(yyvsp[-4].expression_p))[i].second)); ids = vector(); } else if (id && boe->op() == BOT_EQ && ids.empty()) { ids.push_back(id); gens.push_back(Generator(ids,NULL,boe->rhs())); if ((*(yyvsp[-4].expression_p))[i].second) { gens.push_back(Generator(gens.size(),(*(yyvsp[-4].expression_p))[i].second)); } ids = vector(); } else { ParserLocation loc = (*(yyvsp[-4].expression_p))[i].first->loc().parserLocation(); yyerror(&loc, parm, "illegal expression in generator call"); } } } else { ParserLocation loc = (*(yyvsp[-4].expression_p))[i].first->loc().parserLocation(); yyerror(&loc, parm, "illegal expression in generator call"); } } } } if (ids.size() != 0) { yyerror(&(yylsp[-4]), parm, "illegal expression in generator call"); } ParserState* pp = static_cast(parm); if (pp->hadError) { (yyval.expression)=NULL; } else { Generators g; g._g = gens; Comprehension* ac = new Comprehension((yyloc), (yyvsp[-1].expression),g,false); vector args; args.push_back(ac); (yyval.expression)=new Call((yyloc), (yyvsp[-6].sValue), args); } free((yyvsp[-6].sValue)); delete (yyvsp[-4].expression_p); } break; case 272: { (yyval.expression_p)=new vector >; if ((yyvsp[0].expression)) { (yyval.expression_p)->push_back(pair((yyvsp[0].expression),NULL)); } } break; case 273: { (yyval.expression_p)=new vector >; if ((yyvsp[-2].expression) && (yyvsp[0].expression)) { (yyval.expression_p)->push_back(pair((yyvsp[-2].expression),(yyvsp[0].expression))); } } break; case 274: { (yyval.expression_p)=(yyvsp[-2].expression_p); if ((yyval.expression_p) && (yyvsp[0].expression)) (yyval.expression_p)->push_back(pair((yyvsp[0].expression),NULL)); } break; case 275: { (yyval.expression_p)=(yyvsp[-4].expression_p); if ((yyval.expression_p) && (yyvsp[-2].expression) && (yyvsp[0].expression)) (yyval.expression_p)->push_back(pair((yyvsp[-2].expression),(yyvsp[0].expression))); } break; case 276: { if ((yyvsp[-3].expression_v) && (yyvsp[0].expression)) { (yyval.expression)=new Let((yyloc), *(yyvsp[-3].expression_v), (yyvsp[0].expression)); delete (yyvsp[-3].expression_v); } else { (yyval.expression)=NULL; } } break; case 277: { if ((yyvsp[-4].expression_v) && (yyvsp[0].expression)) { (yyval.expression)=new Let((yyloc), *(yyvsp[-4].expression_v), (yyvsp[0].expression)); delete (yyvsp[-4].expression_v); } else { (yyval.expression)=NULL; } } break; case 278: { (yyval.expression_v)=new vector; (yyval.expression_v)->push_back((yyvsp[0].vardeclexpr)); } break; case 279: { (yyval.expression_v)=new vector; if ((yyvsp[0].item)) { ConstraintI* ce = (yyvsp[0].item)->cast(); (yyval.expression_v)->push_back(ce->e()); ce->e(NULL); } } break; case 280: { (yyval.expression_v)=(yyvsp[-2].expression_v); if ((yyval.expression_v) && (yyvsp[0].vardeclexpr)) (yyval.expression_v)->push_back((yyvsp[0].vardeclexpr)); } break; case 281: { (yyval.expression_v)=(yyvsp[-2].expression_v); if ((yyval.expression_v) && (yyvsp[0].item)) { ConstraintI* ce = (yyvsp[0].item)->cast(); (yyval.expression_v)->push_back(ce->e()); ce->e(NULL); } } break; case 284: { (yyval.vardeclexpr) = (yyvsp[-1].vardeclexpr); if ((yyval.vardeclexpr)) (yyval.vardeclexpr)->toplevel(false); if ((yyval.vardeclexpr) && (yyvsp[0].expression_v)) (yyval.vardeclexpr)->addAnnotations(*(yyvsp[0].expression_v)); delete (yyvsp[0].expression_v); } break; case 285: { if ((yyvsp[-3].vardeclexpr)) (yyvsp[-3].vardeclexpr)->e((yyvsp[0].expression)); (yyval.vardeclexpr) = (yyvsp[-3].vardeclexpr); if ((yyval.vardeclexpr)) (yyval.vardeclexpr)->loc((yyloc)); if ((yyval.vardeclexpr)) (yyval.vardeclexpr)->toplevel(false); if ((yyval.vardeclexpr) && (yyvsp[-2].expression_v)) (yyval.vardeclexpr)->addAnnotations(*(yyvsp[-2].expression_v)); delete (yyvsp[-2].expression_v); } break; case 286: { (yyval.expression_v)=NULL; } break; case 288: { (yyval.expression) = (yyvsp[0].expression); } break; case 289: { (yyval.expression) = new Call((yylsp[0]), ASTString("mzn_expression_name"), {(yyvsp[0].expression)}); } break; case 290: { (yyval.expression_v)=new std::vector(1); (*(yyval.expression_v))[0] = (yyvsp[0].expression); } break; case 291: { (yyval.expression_v)=(yyvsp[-2].expression_v); if ((yyval.expression_v)) (yyval.expression_v)->push_back((yyvsp[0].expression)); } break; case 292: { (yyval.sValue)=(yyvsp[0].sValue); } break; case 293: { (yyval.sValue)=strdup("'<->'"); } break; case 294: { (yyval.sValue)=strdup("'->'"); } break; case 295: { (yyval.sValue)=strdup("'<-'"); } break; case 296: { (yyval.sValue)=strdup("'\\/'"); } break; case 297: { (yyval.sValue)=strdup("'xor'"); } break; case 298: { (yyval.sValue)=strdup("'/\\'"); } break; case 299: { (yyval.sValue)=strdup("'<'"); } break; case 300: { (yyval.sValue)=strdup("'>'"); } break; case 301: { (yyval.sValue)=strdup("'<='"); } break; case 302: { (yyval.sValue)=strdup("'>='"); } break; case 303: { (yyval.sValue)=strdup("'='"); } break; case 304: { (yyval.sValue)=strdup("'!='"); } break; case 305: { (yyval.sValue)=strdup("'in'"); } break; case 306: { (yyval.sValue)=strdup("'subset'"); } break; case 307: { (yyval.sValue)=strdup("'superset'"); } break; case 308: { (yyval.sValue)=strdup("'union'"); } break; case 309: { (yyval.sValue)=strdup("'diff'"); } break; case 310: { (yyval.sValue)=strdup("'symdiff'"); } break; case 311: { (yyval.sValue)=strdup("'..'"); } break; case 312: { (yyval.sValue)=strdup("'+'"); } break; case 313: { (yyval.sValue)=strdup("'-'"); } break; case 314: { (yyval.sValue)=strdup("'*'"); } break; case 315: { (yyval.sValue)=strdup("'^'"); } break; case 316: { (yyval.sValue)=strdup("'/'"); } break; case 317: { (yyval.sValue)=strdup("'div'"); } break; case 318: { (yyval.sValue)=strdup("'mod'"); } break; case 319: { (yyval.sValue)=strdup("'intersect'"); } break; case 320: { (yyval.sValue)=strdup("'not'"); } break; case 321: { (yyval.sValue)=strdup("'++'"); } break; default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; *++yylsp = yyloc; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if ! YYERROR_VERBOSE yyerror (&yylloc, parm, YY_("syntax error")); #else # define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ yyssp, yytoken) { char const *yymsgp = YY_("syntax error"); int yysyntax_error_status; yysyntax_error_status = YYSYNTAX_ERROR; if (yysyntax_error_status == 0) yymsgp = yymsg; else if (yysyntax_error_status == 1) { if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); if (!yymsg) { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; yysyntax_error_status = 2; } else { yysyntax_error_status = YYSYNTAX_ERROR; yymsgp = yymsg; } } yyerror (&yylloc, parm, yymsgp); if (yysyntax_error_status == 2) goto yyexhaustedlab; } # undef YYSYNTAX_ERROR #endif } yyerror_range[1] = yylloc; if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval, &yylloc, parm); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers like GCC when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (/*CONSTCOND*/ 0) goto yyerrorlab; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yyerror_range[1] = *yylsp; yydestruct ("Error: popping", yystos[yystate], yyvsp, yylsp, parm); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END yyerror_range[2] = yylloc; /* Using YYLLOC is tempting, but would change the location of the lookahead. YYLOC is available though. */ YYLLOC_DEFAULT (yyloc, yyerror_range, 2); *++yylsp = yyloc; /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #if !defined yyoverflow || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: yyerror (&yylloc, parm, YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif yyreturn: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval, &yylloc, parm); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", yystos[*yyssp], yyvsp, yylsp, parm); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif #if YYERROR_VERBOSE if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif return yyresult; } libminizinc-2.4.2/lib/cached/regex_lexer.yy.cpp000066400000000000000000001456511360574160400215020ustar00rootroot00000000000000 #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define yy_create_buffer regex_yy_create_buffer #define yy_delete_buffer regex_yy_delete_buffer #define yy_scan_buffer regex_yy_scan_buffer #define yy_scan_string regex_yy_scan_string #define yy_scan_bytes regex_yy_scan_bytes #define yy_init_buffer regex_yy_init_buffer #define yy_flush_buffer regex_yy_flush_buffer #define yy_load_buffer_state regex_yy_load_buffer_state #define yy_switch_to_buffer regex_yy_switch_to_buffer #define yypush_buffer_state regex_yypush_buffer_state #define yypop_buffer_state regex_yypop_buffer_state #define yyensure_buffer_stack regex_yyensure_buffer_stack #define yy_flex_debug regex_yy_flex_debug #define yyin regex_yyin #define yyleng regex_yyleng #define yylex regex_yylex #define yylineno regex_yylineno #define yyout regex_yyout #define yyrestart regex_yyrestart #define yytext regex_yytext #define yywrap regex_yywrap #define yyalloc regex_yyalloc #define yyrealloc regex_yyrealloc #define yyfree regex_yyfree #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 6 #define YY_FLEX_SUBMINOR_VERSION 4 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif #ifdef yy_create_buffer #define regex_yy_create_buffer_ALREADY_DEFINED #else #define yy_create_buffer regex_yy_create_buffer #endif #ifdef yy_delete_buffer #define regex_yy_delete_buffer_ALREADY_DEFINED #else #define yy_delete_buffer regex_yy_delete_buffer #endif #ifdef yy_scan_buffer #define regex_yy_scan_buffer_ALREADY_DEFINED #else #define yy_scan_buffer regex_yy_scan_buffer #endif #ifdef yy_scan_string #define regex_yy_scan_string_ALREADY_DEFINED #else #define yy_scan_string regex_yy_scan_string #endif #ifdef yy_scan_bytes #define regex_yy_scan_bytes_ALREADY_DEFINED #else #define yy_scan_bytes regex_yy_scan_bytes #endif #ifdef yy_init_buffer #define regex_yy_init_buffer_ALREADY_DEFINED #else #define yy_init_buffer regex_yy_init_buffer #endif #ifdef yy_flush_buffer #define regex_yy_flush_buffer_ALREADY_DEFINED #else #define yy_flush_buffer regex_yy_flush_buffer #endif #ifdef yy_load_buffer_state #define regex_yy_load_buffer_state_ALREADY_DEFINED #else #define yy_load_buffer_state regex_yy_load_buffer_state #endif #ifdef yy_switch_to_buffer #define regex_yy_switch_to_buffer_ALREADY_DEFINED #else #define yy_switch_to_buffer regex_yy_switch_to_buffer #endif #ifdef yypush_buffer_state #define regex_yypush_buffer_state_ALREADY_DEFINED #else #define yypush_buffer_state regex_yypush_buffer_state #endif #ifdef yypop_buffer_state #define regex_yypop_buffer_state_ALREADY_DEFINED #else #define yypop_buffer_state regex_yypop_buffer_state #endif #ifdef yyensure_buffer_stack #define regex_yyensure_buffer_stack_ALREADY_DEFINED #else #define yyensure_buffer_stack regex_yyensure_buffer_stack #endif #ifdef yylex #define regex_yylex_ALREADY_DEFINED #else #define yylex regex_yylex #endif #ifdef yyrestart #define regex_yyrestart_ALREADY_DEFINED #else #define yyrestart regex_yyrestart #endif #ifdef yylex_init #define regex_yylex_init_ALREADY_DEFINED #else #define yylex_init regex_yylex_init #endif #ifdef yylex_init_extra #define regex_yylex_init_extra_ALREADY_DEFINED #else #define yylex_init_extra regex_yylex_init_extra #endif #ifdef yylex_destroy #define regex_yylex_destroy_ALREADY_DEFINED #else #define yylex_destroy regex_yylex_destroy #endif #ifdef yyget_debug #define regex_yyget_debug_ALREADY_DEFINED #else #define yyget_debug regex_yyget_debug #endif #ifdef yyset_debug #define regex_yyset_debug_ALREADY_DEFINED #else #define yyset_debug regex_yyset_debug #endif #ifdef yyget_extra #define regex_yyget_extra_ALREADY_DEFINED #else #define yyget_extra regex_yyget_extra #endif #ifdef yyset_extra #define regex_yyset_extra_ALREADY_DEFINED #else #define yyset_extra regex_yyset_extra #endif #ifdef yyget_in #define regex_yyget_in_ALREADY_DEFINED #else #define yyget_in regex_yyget_in #endif #ifdef yyset_in #define regex_yyset_in_ALREADY_DEFINED #else #define yyset_in regex_yyset_in #endif #ifdef yyget_out #define regex_yyget_out_ALREADY_DEFINED #else #define yyget_out regex_yyget_out #endif #ifdef yyset_out #define regex_yyset_out_ALREADY_DEFINED #else #define yyset_out regex_yyset_out #endif #ifdef yyget_leng #define regex_yyget_leng_ALREADY_DEFINED #else #define yyget_leng regex_yyget_leng #endif #ifdef yyget_text #define regex_yyget_text_ALREADY_DEFINED #else #define yyget_text regex_yyget_text #endif #ifdef yyget_lineno #define regex_yyget_lineno_ALREADY_DEFINED #else #define yyget_lineno regex_yyget_lineno #endif #ifdef yyset_lineno #define regex_yyset_lineno_ALREADY_DEFINED #else #define yyset_lineno regex_yyset_lineno #endif #ifdef yywrap #define regex_yywrap_ALREADY_DEFINED #else #define yywrap regex_yywrap #endif #ifdef yyalloc #define regex_yyalloc_ALREADY_DEFINED #else #define yyalloc regex_yyalloc #endif #ifdef yyrealloc #define regex_yyrealloc_ALREADY_DEFINED #else #define yyrealloc regex_yyrealloc #endif #ifdef yyfree #define regex_yyfree_ALREADY_DEFINED #else #define yyfree regex_yyfree #endif #ifdef yytext #define regex_yytext_ALREADY_DEFINED #else #define yytext regex_yytext #endif #ifdef yyleng #define regex_yyleng_ALREADY_DEFINED #else #define yyleng regex_yyleng #endif #ifdef yyin #define regex_yyin_ALREADY_DEFINED #else #define yyin regex_yyin #endif #ifdef yyout #define regex_yyout_ALREADY_DEFINED #else #define yyout regex_yyout #endif #ifdef yy_flex_debug #define regex_yy_flex_debug_ALREADY_DEFINED #else #define yy_flex_debug regex_yy_flex_debug #endif #ifdef yylineno #define regex_yylineno_ALREADY_DEFINED #else #define yylineno regex_yylineno #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #ifndef SIZE_MAX #define SIZE_MAX (~(size_t)0) #endif #endif /* ! C99 */ #endif /* ! FLEXINT_H */ /* begin standard C++ headers. */ /* TODO: this is always defined, so inline it */ #define yyconst const #if defined(__GNUC__) && __GNUC__ >= 3 #define yynoreturn __attribute__((__noreturn__)) #else #define yynoreturn #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an * integer in range [0..255] for use as an array index. */ #define YY_SC_TO_UI(c) ((YY_CHAR) (c)) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart( yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k. * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. * Ditto for the __ia64__ case accordingly. */ #define YY_BUF_SIZE 32768 #else #define YY_BUF_SIZE 16384 #endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif extern int yyleng; extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) #define YY_LINENO_REWIND_TO(ptr) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, (yytext_ptr) ) #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ int yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static int yy_n_chars; /* number of characters read into yy_ch_buf */ int yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = NULL; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches * instead of setting up a fresh yyin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void yyrestart ( FILE *input_file ); void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer ); YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size ); void yy_delete_buffer ( YY_BUFFER_STATE b ); void yy_flush_buffer ( YY_BUFFER_STATE b ); void yypush_buffer_state ( YY_BUFFER_STATE new_buffer ); void yypop_buffer_state ( void ); static void yyensure_buffer_stack ( void ); static void yy_load_buffer_state ( void ); static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file ); #define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER ) YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size ); YY_BUFFER_STATE yy_scan_string ( const char *yy_str ); YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len ); void *yyalloc ( yy_size_t ); void *yyrealloc ( void *, yy_size_t ); void yyfree ( void * ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ #define regex_yywrap() (/*CONSTCOND*/1) #define YY_SKIP_YYWRAP typedef flex_uint8_t YY_CHAR; FILE *yyin = NULL, *yyout = NULL; typedef int yy_state_type; extern int yylineno; int yylineno = 1; extern char *yytext; #ifdef yytext_ptr #undef yytext_ptr #endif #define yytext_ptr yytext static yy_state_type yy_get_previous_state ( void ); static yy_state_type yy_try_NUL_trans ( yy_state_type current_state ); static int yy_get_next_buffer ( void ); static void yynoreturn yy_fatal_error ( const char* msg ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ yyleng = (int) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; #define YY_NUM_RULES 20 #define YY_END_OF_BUFFER 21 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static const flex_int16_t yy_accept[29] = { 0, 0, 0, 21, 19, 1, 1, 19, 6, 7, 5, 4, 11, 15, 12, 2, 8, 17, 13, 14, 16, 9, 3, 10, 0, 18, 2, 17, 0 } ; static const YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 5, 6, 7, 8, 9, 10, 11, 12, 1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1, 1, 1, 14, 1, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 4, 17, 18, 19, 1, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 20, 21, 22, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static const YY_CHAR yy_meta[23] = { 0, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static const flex_int16_t yy_base[30] = { 0, 0, 0, 34, 35, 35, 35, 28, 35, 35, 35, 35, 35, 35, 35, 19, 35, 10, 35, 35, 35, 35, 35, 35, 26, 35, 15, 11, 35, 26 } ; static const flex_int16_t yy_def[30] = { 0, 28, 1, 28, 28, 28, 28, 29, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 28, 28, 28, 0, 28 } ; static const flex_int16_t yy_nxt[58] = { 0, 4, 5, 6, 4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 4, 21, 22, 23, 27, 27, 27, 27, 24, 26, 27, 27, 25, 26, 25, 28, 3, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28 } ; static const flex_int16_t yy_chk[58] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 27, 17, 27, 29, 26, 17, 27, 24, 15, 7, 3, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; extern int yy_flex_debug; int yy_flex_debug = 0; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *yytext; /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Jip J. Dekker */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #define YY_DECL int yylex() #include #define INITIAL 0 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif static int yy_init_globals ( void ); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy ( void ); int yyget_debug ( void ); void yyset_debug ( int debug_flag ); YY_EXTRA_TYPE yyget_extra ( void ); void yyset_extra ( YY_EXTRA_TYPE user_defined ); FILE *yyget_in ( void ); void yyset_in ( FILE * _in_str ); FILE *yyget_out ( void ); void yyset_out ( FILE * _out_str ); int yyget_leng ( void ); char *yyget_text ( void ); int yyget_lineno ( void ); void yyset_lineno ( int _line_number ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap ( void ); #else extern int yywrap ( void ); #endif #endif #ifndef YY_NO_UNPUT static void yyunput ( int c, char *buf_ptr ); #endif #ifndef yytext_ptr static void yy_flex_strncpy ( char *, const char *, int ); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen ( const char * ); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput ( void ); #else static int input ( void ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k */ #define YY_READ_BUF_SIZE 16384 #else #define YY_READ_BUF_SIZE 8192 #endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ int n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex (void); #define YY_DECL int yylex (void) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK /*LINTED*/break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { yy_state_type yy_current_state; char *yy_cp, *yy_bp; int yy_act; if ( !(yy_init) ) { (yy_init) = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! (yy_start) ) (yy_start) = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE ); } yy_load_buffer_state( ); } { while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { yy_cp = (yy_c_buf_p); /* Support of yytext. */ *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = (yy_start); yy_match: do { YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 29 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 35 ); yy_find_action: yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = (yy_hold_char); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; case 1: /* rule 1 can match eol */ YY_RULE_SETUP { /* ignore white space */ } YY_BREAK case 2: YY_RULE_SETUP { regex_yylval.iValue = std::atoi(regex_yytext); return R_INTEGER; } YY_BREAK case 3: YY_RULE_SETUP { return R_UNION; } YY_BREAK case 4: YY_RULE_SETUP { return R_PLUS; } YY_BREAK case 5: YY_RULE_SETUP { return R_STAR; } YY_BREAK case 6: YY_RULE_SETUP { return R_GROUP_OPEN; } YY_BREAK case 7: YY_RULE_SETUP { return R_GROUP_CLOSE; } YY_BREAK case 8: YY_RULE_SETUP { return R_OPTIONAL; } YY_BREAK case 9: YY_RULE_SETUP { return R_QUANT_OPEN; } YY_BREAK case 10: YY_RULE_SETUP { return R_QUANT_CLOSE; } YY_BREAK case 11: YY_RULE_SETUP { return R_COMMA; } YY_BREAK case 12: YY_RULE_SETUP { return R_ANY; } YY_BREAK case 13: YY_RULE_SETUP { return R_CLASS_OPEN; } YY_BREAK case 14: YY_RULE_SETUP { return R_CLASS_CLOSE; } YY_BREAK case 15: YY_RULE_SETUP { return R_CLASS_RANGE; } YY_BREAK case 16: YY_RULE_SETUP { return R_CLASS_NEG; } YY_BREAK case 17: YY_RULE_SETUP { regex_yylval.sValue = strdup(yytext); return R_IDENTIFIER; } YY_BREAK case 18: YY_RULE_SETUP { regex_yylval.sValue = strdup(yytext); return R_IDENTIFIER; } YY_BREAK case 19: YY_RULE_SETUP { /* Catch all */ throw std::runtime_error("Illegal token in regular expression: '" + std::string(regex_yytext) + "'"); } YY_BREAK case 20: YY_RULE_SETUP ECHO; YY_BREAK case YY_STATE_EOF(INITIAL): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = (yy_c_buf_p); goto yy_find_action; } } else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { (yy_did_buffer_switch_on_eof) = 0; if ( yywrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: (yy_c_buf_p) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of user's declarations */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (void) { char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; char *source = (yytext_ptr); int number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1); for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; int yy_c_buf_p_offset = (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc( (void *) b->yy_ch_buf, (yy_size_t) (b->yy_buf_size + 2) ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = NULL; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), (yy_n_chars), num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart( yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); /* "- 2" to take care of EOB's */ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); } (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (void) { yy_state_type yy_current_state; char *yy_cp; yy_current_state = (yy_start); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 4); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 29 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { int yy_is_jam; char *yy_cp = (yy_c_buf_p); YY_CHAR yy_c = 4; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 29 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; yy_is_jam = (yy_current_state == 28); return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_UNPUT static void yyunput (int c, char * yy_bp ) { char *yy_cp; yy_cp = (yy_c_buf_p); /* undo effects of setting up yytext */ *yy_cp = (yy_hold_char); if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ int number_to_move = (yy_n_chars) + 2; char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; char *source = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) *--dest = *--source; yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size; if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); } *--yy_cp = (char) c; (yytext_ptr) = yy_bp; (yy_hold_char) = *yy_cp; (yy_c_buf_p) = yy_cp; } #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) #else static int input (void) #endif { int c; *(yy_c_buf_p) = (yy_hold_char); if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ *(yy_c_buf_p) = '\0'; else { /* need more input */ int offset = (int) ((yy_c_buf_p) - (yytext_ptr)); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart( yyin ); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( ) ) return 0; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ *(yy_c_buf_p) = '\0'; /* preserve yytext */ (yy_hold_char) = *++(yy_c_buf_p); return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file ) { if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE ); } yy_init_buffer( YY_CURRENT_BUFFER, input_file ); yy_load_buffer_state( ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) { /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ (yy_did_buffer_switch_on_eof) = 1; } static void yy_load_buffer_state (void) { (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; (yy_hold_char) = *(yy_c_buf_p); } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer( b, file ); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * */ void yy_delete_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree( (void *) b->yy_ch_buf ); yyfree( (void *) b ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) { int oerrno = errno; yy_flush_buffer( b ); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * */ void yy_flush_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) { if (new_buffer == NULL) return; yyensure_buffer_stack(); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) (yy_buffer_stack_top)++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void yypop_buffer_state (void) { if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; if ((yy_buffer_stack_top) > 0) --(yy_buffer_stack_top); if (YY_CURRENT_BUFFER) { yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (void) { yy_size_t num_to_alloc; if (!(yy_buffer_stack)) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; } if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc ((yy_buffer_stack), num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); /* zero only the new slots.*/ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return NULL; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = NULL; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer( b ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (const char * yystr ) { return yy_scan_bytes( yystr, (int) strlen(yystr) ); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param yybytes the byte buffer to scan * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len ) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = (yy_size_t) (_yybytes_len + 2); buf = (char *) yyalloc( n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer( buf, n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yynoreturn yy_fatal_error (const char* msg ) { fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = (yy_hold_char); \ (yy_c_buf_p) = yytext + yyless_macro_arg; \ (yy_hold_char) = *(yy_c_buf_p); \ *(yy_c_buf_p) = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the current line number. * */ int yyget_lineno (void) { return yylineno; } /** Get the input stream. * */ FILE *yyget_in (void) { return yyin; } /** Get the output stream. * */ FILE *yyget_out (void) { return yyout; } /** Get the length of the current token. * */ int yyget_leng (void) { return yyleng; } /** Get the current token. * */ char *yyget_text (void) { return yytext; } /** Set the current line number. * @param _line_number line number * */ void yyset_lineno (int _line_number ) { yylineno = _line_number; } /** Set the input stream. This does not discard the current * input buffer. * @param _in_str A readable stream. * * @see yy_switch_to_buffer */ void yyset_in (FILE * _in_str ) { yyin = _in_str ; } void yyset_out (FILE * _out_str ) { yyout = _out_str ; } int yyget_debug (void) { return yy_flex_debug; } void yyset_debug (int _bdebug ) { yy_flex_debug = _bdebug ; } static int yy_init_globals (void) { /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ (yy_buffer_stack) = NULL; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; (yy_c_buf_p) = NULL; (yy_init) = 0; (yy_start) = 0; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = NULL; yyout = NULL; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (void) { /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer( YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(); } /* Destroy the stack itself. */ yyfree((yy_buffer_stack) ); (yy_buffer_stack) = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * yylex() is called, initialization will occur. */ yy_init_globals( ); return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, const char * s2, int n ) { int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (const char * s ) { int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (yy_size_t size ) { return malloc(size); } void *yyrealloc (void * ptr, yy_size_t size ) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return realloc(ptr, size); } void yyfree (void * ptr ) { free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" libminizinc-2.4.2/lib/cached/regex_parser.tab.cpp000066400000000000000000001417151360574160400217610ustar00rootroot00000000000000/* A Bison parser, made by GNU Bison 3.1. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ #define YYBISON_VERSION "3.1" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Substitute the variable and function names. */ #define yyparse regex_yyparse #define yylex regex_yylex #define yyerror regex_yyerror #define yydebug regex_yydebug #define yynerrs regex_yynerrs #define yylval regex_yylval #define yychar regex_yychar /* Copy the first part of user declarations. */ #include #include #include #include #include #include #include using namespace Gecode; using namespace MiniZinc; typedef struct yy_buffer_state *YY_BUFFER_STATE; YY_BUFFER_STATE regex_yy_scan_string ( const char* yy_str ); extern int yylex(); extern FILE* yyin; typedef struct REContext{ REG* expr; const IntSetVal& dom; const std::unordered_map& idMap; } REContext; void yyerror(REContext& ctx, const char* s); # ifndef YY_NULLPTR # if defined __cplusplus && 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else # define YYERROR_VERBOSE 0 #endif /* In a future release of Bison, this section will be replaced by #include "regex_parser.tab.hh". */ #ifndef YY_REGEX_YY_USERS_TACK_PROGRAMMING_MINIZINC_LIBMZN_BUILD_XCODE_INCLUDE_MINIZINC_SUPPORT_REGEX_PARSER_TAB_HH_INCLUDED # define YY_REGEX_YY_USERS_TACK_PROGRAMMING_MINIZINC_LIBMZN_BUILD_XCODE_INCLUDE_MINIZINC_SUPPORT_REGEX_PARSER_TAB_HH_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int regex_yydebug; #endif /* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { R_INTEGER = 258, R_GROUP_OPEN = 259, R_GROUP_CLOSE = 260, R_STAR = 261, R_PLUS = 262, R_ANY = 263, R_UNION = 264, R_OPTIONAL = 265, R_QUANT_OPEN = 266, R_QUANT_CLOSE = 267, R_COMMA = 268, R_CLASS_OPEN = 269, R_CLASS_CLOSE = 270, R_CLASS_RANGE = 271, R_CLASS_NEG = 272, R_IDENTIFIER = 273 }; #endif /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { int iValue; char* sValue; std::set* setValue; Gecode::REG* rValue; }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif extern YYSTYPE regex_yylval; int regex_yyparse (REContext& ctx); #endif /* !YY_REGEX_YY_USERS_TACK_PROGRAMMING_MINIZINC_LIBMZN_BUILD_XCODE_INCLUDE_MINIZINC_SUPPORT_REGEX_PARSER_TAB_HH_INCLUDED */ /* Copy the second part of user declarations. */ #ifdef short # undef short #endif #ifdef YYTYPE_UINT8 typedef YYTYPE_UINT8 yytype_uint8; #else typedef unsigned char yytype_uint8; #endif #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else typedef unsigned short yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else typedef short yytype_int16; #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif ! defined YYSIZE_T # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned # endif #endif #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE # if (defined __GNUC__ \ && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C # define YY_ATTRIBUTE(Spec) __attribute__(Spec) # else # define YY_ATTRIBUTE(Spec) /* empty */ # endif #endif #ifndef YY_ATTRIBUTE_PURE # define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) #endif #ifndef YY_ATTRIBUTE_UNUSED # define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) #endif #if !defined _Noreturn \ && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) # if defined _MSC_VER && 1200 <= _MSC_VER # define _Noreturn __declspec (noreturn) # else # define _Noreturn YY_ATTRIBUTE ((__noreturn__)) # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(E) ((void) (E)) #else # define YYUSE(E) /* empty */ #endif #if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ /* Suppress an incorrect diagnostic about yylval being uninitialized. */ # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yytype_int16 yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 17 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 34 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 19 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 9 /* YYNRULES -- Number of rules. */ #define YYNRULES 24 /* YYNSTATES -- Number of states. */ #define YYNSTATES 38 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 273 #define YYTRANSLATE(YYX) \ ((unsigned) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex, without out-of-bounds checking. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { 0, 73, 73, 80, 81, 89, 90, 98, 99, 104, 109, 114, 119, 124, 131, 133, 138, 148, 163, 167, 168, 178, 182, 196, 197 }; #endif #if YYDEBUG || YYERROR_VERBOSE || 0 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "$end", "error", "$undefined", "R_INTEGER", "\"(\"", "\")\"", "\"*\"", "\"+\"", "\".\"", "\"|\"", "\"?\"", "\"{\"", "\"}\"", "\",\"", "\"[\"", "\"]\"", "\"-\"", "\"^\"", "R_IDENTIFIER", "$accept", "regex", "expression", "term", "factor", "atom", "set_items", "set_item", "literal", YY_NULLPTR }; #endif # ifdef YYPRINT /* YYTOKNUM[NUM] -- (External) token number corresponding to the (internal) symbol number NUM (which must be that of a token). */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273 }; # endif #define YYPACT_NINF -8 #define yypact_value_is_default(Yystate) \ (!!((Yystate) == (-8))) #define YYTABLE_NINF -1 #define yytable_value_is_error(Yytable_value) \ 0 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int8 yypact[] = { 0, -8, 0, -8, 2, -8, 13, -8, -7, 0, 16, -8, 10, 3, 18, 3, 9, -8, 0, -8, -8, -8, -8, 25, -8, 19, -8, -8, 3, -8, 17, -8, -8, -8, 4, 20, -8, -8 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { 0, 23, 0, 15, 0, 24, 0, 2, 3, 5, 7, 14, 0, 0, 0, 19, 21, 1, 0, 6, 8, 9, 10, 0, 18, 0, 16, 20, 0, 4, 0, 17, 22, 11, 0, 0, 12, 13 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -8, -8, -1, 22, -8, -8, -3, -8, -4 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { -1, 6, 7, 8, 9, 10, 14, 15, 11 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_uint8 yytable[] = { 16, 12, 18, 1, 2, 1, 1, 35, 3, 16, 25, 16, 27, 17, 4, 24, 36, 29, 5, 13, 5, 5, 20, 21, 32, 28, 22, 23, 30, 33, 34, 19, 37, 26, 31 }; static const yytype_uint8 yycheck[] = { 4, 2, 9, 3, 4, 3, 3, 3, 8, 13, 13, 15, 15, 0, 14, 5, 12, 18, 18, 17, 18, 18, 6, 7, 28, 16, 10, 11, 3, 12, 13, 9, 12, 15, 15 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 3, 4, 8, 14, 18, 20, 21, 22, 23, 24, 27, 21, 17, 25, 26, 27, 0, 9, 22, 6, 7, 10, 11, 5, 25, 15, 25, 16, 21, 3, 15, 27, 12, 13, 3, 12, 12 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { 0, 19, 20, 21, 21, 22, 22, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 25, 25, 26, 26, 27, 27 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 1, 1, 3, 1, 2, 1, 2, 2, 2, 4, 5, 6, 1, 1, 3, 4, 3, 1, 2, 1, 3, 1, 1 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (ctx, YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Error token number */ #define YYTERROR 1 #define YYERRCODE 256 /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) /* This macro is provided for backward compatibility. */ #ifndef YY_LOCATION_PRINT # define YY_LOCATION_PRINT(File, Loc) ((void) 0) #endif # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Type, Value, ctx); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*----------------------------------------. | Print this symbol's value on YYOUTPUT. | `----------------------------------------*/ static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, REContext& ctx) { FILE *yyo = yyoutput; YYUSE (yyo); YYUSE (ctx); if (!yyvaluep) return; # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # endif YYUSE (yytype); } /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, REContext& ctx) { YYFPRINTF (yyoutput, "%s %s (", yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); yy_symbol_value_print (yyoutput, yytype, yyvaluep, ctx); YYFPRINTF (yyoutput, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, REContext& ctx) { unsigned long yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yystos[yyssp[yyi + 1 - yynrhs]], &(yyvsp[(yyi + 1) - (yynrhs)]) , ctx); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, Rule, ctx); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen strlen # else /* Return the length of YYSTR. */ static YYSIZE_T yystrlen (const char *yystr) { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif # endif # ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ static char * yystpcpy (char *yydest, const char *yysrc) { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif # ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYSIZE_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYSIZE_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; /* Fall through. */ default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (! yyres) return yystrlen (yystr); return yystpcpy (yyres, yystr) - yyres; } # endif /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message about the unexpected token YYTOKEN for the state stack whose top is YYSSP. Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is not large enough to hold the message. In that case, also set *YYMSG_ALLOC to the required number of bytes. Return 2 if the required number of bytes is too large to store. */ static int yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, yytype_int16 *yyssp, int yytoken) { YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); YYSIZE_T yysize = yysize0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ const char *yyformat = YY_NULLPTR; /* Arguments of yyformat. */ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; /* Number of reported tokens (one for the "unexpected", one per "expected"). */ int yycount = 0; /* There are many possibilities here to consider: - If this state is a consistent state with a default action, then the only way this function was invoked is if the default action is an error action. In that case, don't check for expected tokens because there are none. - The only way there can be no lookahead present (in yychar) is if this state is a consistent state with a default action. Thus, detecting the absence of a lookahead is sufficient to determine that there is no unexpected or expected token to report. In that case, just report a simple "syntax error". - Don't assume there isn't a lookahead just because this state is a consistent state with a default action. There might have been a previous inconsistent state, consistent state with a non-default action, or user semantic action that manipulated yychar. - Of course, the expected token list depends on states to have correct lookahead information, and it depends on the parser not to perform extra reductions after fetching a lookahead from the scanner and before detecting a syntax error. Thus, state merging (from LALR or IELR) and default reductions corrupt the expected token list. However, the list is correct for canonical LR with one exception: it will still contain any token that will not be accepted due to an error action in a later state. */ if (yytoken != YYEMPTY) { int yyn = yypact[*yyssp]; yyarg[yycount++] = yytname[yytoken]; if (!yypact_value_is_default (yyn)) { /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. In other words, skip the first -YYN actions for this state because they are default actions. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yyx; for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR && !yytable_value_is_error (yytable[yyx + yyn])) { if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) { yycount = 1; yysize = yysize0; break; } yyarg[yycount++] = yytname[yyx]; { YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; } } } } switch (yycount) { # define YYCASE_(N, S) \ case N: \ yyformat = S; \ break default: /* Avoid compiler warnings. */ YYCASE_(0, YY_("syntax error")); YYCASE_(1, YY_("syntax error, unexpected %s")); YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); # undef YYCASE_ } { YYSIZE_T yysize1 = yysize + yystrlen (yyformat); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; } if (*yymsg_alloc < yysize) { *yymsg_alloc = 2 * yysize; if (! (yysize <= *yymsg_alloc && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; return 1; } /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ { char *yyp = *yymsg; int yyi = 0; while ((*yyp = *yyformat) != '\0') if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yyarg[yyi++]); yyformat += 2; } else { yyp++; yyformat++; } } return 0; } #endif /* YYERROR_VERBOSE */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, REContext& ctx) { YYUSE (yyvaluep); YYUSE (ctx); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YYUSE (yytype); YY_IGNORE_MAYBE_UNINITIALIZED_END } /* The lookahead symbol. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ int yyparse (REContext& ctx) { int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* The stacks and their tools: 'yyss': related to states. 'yyvs': related to semantic values. Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ yytype_int16 yyssa[YYINITDEPTH]; yytype_int16 *yyss; yytype_int16 *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs; YYSTYPE *yyvsp; YYSIZE_T yystacksize; int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ int yytoken = 0; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; yyssp = yyss = yyssa; yyvsp = yyvs = yyvsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyexhaustedlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yytype_int16 *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = yylex (); } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); /* Discard the shifted token. */ yychar = YYEMPTY; yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 2: { *ctx.expr = (*(yyvsp[0].rValue)); delete (yyvsp[0].rValue); } break; case 4: { *(yyvsp[-2].rValue) = *(yyvsp[-2].rValue) | *(yyvsp[0].rValue); delete (yyvsp[0].rValue); (yyval.rValue) = (yyvsp[-2].rValue); } break; case 6: { *(yyvsp[-1].rValue) = *(yyvsp[-1].rValue) + *(yyvsp[0].rValue); delete (yyvsp[0].rValue); (yyval.rValue) = (yyvsp[-1].rValue); } break; case 8: { *(yyvsp[-1].rValue) = *(*(yyvsp[-1].rValue)); (yyval.rValue) = (yyvsp[-1].rValue); } break; case 9: { *(yyvsp[-1].rValue) = +(*(yyvsp[-1].rValue)); (yyval.rValue) = (yyvsp[-1].rValue); } break; case 10: { *(yyvsp[-1].rValue) = (*(yyvsp[-1].rValue))(0, 1); (yyval.rValue) = (yyvsp[-1].rValue); } break; case 11: { *(yyvsp[-3].rValue) = (*(yyvsp[-3].rValue))((yyvsp[-1].iValue), (yyvsp[-1].iValue)); (yyval.rValue) = (yyvsp[-3].rValue); } break; case 12: { *(yyvsp[-4].rValue) = (*(yyvsp[-4].rValue))((yyvsp[-2].iValue)); (yyval.rValue) = (yyvsp[-4].rValue); } break; case 13: { *(yyvsp[-5].rValue) = (*(yyvsp[-5].rValue))((yyvsp[-3].iValue), (yyvsp[-1].iValue)); (yyval.rValue) = (yyvsp[-5].rValue); } break; case 14: { (yyval.rValue) = new REG((yyvsp[0].iValue)); } break; case 15: { IntArgs range = IntArgs::create(ctx.dom.max().toInt() - ctx.dom.min().toInt() + 1, ctx.dom.min().toInt()); (yyval.rValue) = new REG(range); } break; case 16: { std::vector v; v.reserve((yyvsp[-1].setValue)->size()); for(auto i : *(yyvsp[-1].setValue)) { v.push_back(i); } delete (yyvsp[-1].setValue); (yyval.rValue) = new REG(IntArgs(v)); } break; case 17: { std::vector diff; std::set domain; for(int i = ctx.dom.min().toInt(); i<=ctx.dom.max().toInt(); ++i) { domain.insert(i); } std::set_difference( domain.begin(), domain.end(), (yyvsp[-1].setValue)->begin(), (yyvsp[-1].setValue)->end(), std::inserter(diff, diff.begin()) ); delete (yyvsp[-1].setValue); (yyval.rValue) = new REG(IntArgs(diff)); } break; case 18: { (yyval.rValue) = (yyvsp[-1].rValue); } break; case 20: { (yyval.setValue) = (yyvsp[-1].setValue); for (auto i : *(yyvsp[0].setValue)) { (yyvsp[-1].setValue)->insert(i); } delete (yyvsp[0].setValue); } break; case 21: { (yyval.setValue) = new std::set({(yyvsp[0].iValue)}); } break; case 22: { int from = (yyvsp[-2].iValue); int to = (yyvsp[0].iValue); if (to < from) { std::swap(from,to); } (yyval.setValue) = new std::set; for(int i = from; i<=to; ++i) { (yyval.setValue)->insert(i); } } break; case 24: { std::string s((yyvsp[0].sValue)); auto find = ctx.idMap.find(s); if (find == ctx.idMap.end()) { throw std::runtime_error("Unknown identifier: " + s); } (yyval.iValue) = find->second; } break; default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if ! YYERROR_VERBOSE yyerror (ctx, YY_("syntax error")); #else # define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ yyssp, yytoken) { char const *yymsgp = YY_("syntax error"); int yysyntax_error_status; yysyntax_error_status = YYSYNTAX_ERROR; if (yysyntax_error_status == 0) yymsgp = yymsg; else if (yysyntax_error_status == 1) { if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); if (!yymsg) { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; yysyntax_error_status = 2; } else { yysyntax_error_status = YYSYNTAX_ERROR; yymsgp = yymsg; } } yyerror (ctx, yymsgp); if (yysyntax_error_status == 2) goto yyexhaustedlab; } # undef YYSYNTAX_ERROR #endif } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval, ctx); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers like GCC when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (/*CONSTCOND*/ 0) goto yyerrorlab; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", yystos[yystate], yyvsp, ctx); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #if !defined yyoverflow || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: yyerror (ctx, YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif yyreturn: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval, ctx); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", yystos[*yyssp], yyvsp, ctx); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif #if YYERROR_VERBOSE if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif return yyresult; } void yyerror(REContext& ctx, const char* s) { // TODO: Add error location throw std::runtime_error("Cannot parse regular expression: " + std::string(s)); } std::unique_ptr regex_from_string(const std::string& regex_str, const IntSetVal& domain, const std::unordered_map& identifiers) { REG* expr = new REG(); regex_yy_scan_string(regex_str.c_str()); REContext rctx = REContext{expr, domain, identifiers}; int err = yyparse(rctx); if (err != 0) { throw std::runtime_error("Cannot parse regular expression, error code " + std::to_string(err)); } return std::unique_ptr(expr); } libminizinc-2.4.2/lib/cdecode.c000066400000000000000000000047331360574160400163430ustar00rootroot00000000000000/* cdecoder.c - c source to a base64 decoding algorithm implementation This is part of the libb64 project, and has been placed in the public domain. For details, see http://sourceforge.net/projects/libb64 */ #include int base64_decode_value(char value_in) { static const char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51}; static const char decoding_size = sizeof(decoding); value_in -= 43; if (value_in < 0 || value_in >= decoding_size) return -1; return decoding[(int)value_in]; } void base64_init_decodestate(base64_decodestate* state_in) { state_in->step = step_a; state_in->plainchar = 0; } int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in) { const char* codechar = code_in; char* plainchar = plaintext_out; char fragment; *plainchar = state_in->plainchar; switch (state_in->step) { while (1) { case step_a: do { if (codechar == code_in+length_in) { state_in->step = step_a; state_in->plainchar = *plainchar; return plainchar - plaintext_out; } fragment = (char)base64_decode_value(*codechar++); } while (fragment < 0); *plainchar = (fragment & 0x03f) << 2; case step_b: do { if (codechar == code_in+length_in) { state_in->step = step_b; state_in->plainchar = *plainchar; return plainchar - plaintext_out; } fragment = (char)base64_decode_value(*codechar++); } while (fragment < 0); *plainchar++ |= (fragment & 0x030) >> 4; *plainchar = (fragment & 0x00f) << 4; case step_c: do { if (codechar == code_in+length_in) { state_in->step = step_c; state_in->plainchar = *plainchar; return plainchar - plaintext_out; } fragment = (char)base64_decode_value(*codechar++); } while (fragment < 0); *plainchar++ |= (fragment & 0x03c) >> 2; *plainchar = (fragment & 0x003) << 6; case step_d: do { if (codechar == code_in+length_in) { state_in->step = step_d; state_in->plainchar = *plainchar; return plainchar - plaintext_out; } fragment = (char)base64_decode_value(*codechar++); } while (fragment < 0); *plainchar++ |= (fragment & 0x03f); } } /* control should not reach here */ return plainchar - plaintext_out; } libminizinc-2.4.2/lib/cencode.c000066400000000000000000000050211360574160400163440ustar00rootroot00000000000000/* cencoder.c - c source to a base64 encoding algorithm implementation This is part of the libb64 project, and has been placed in the public domain. For details, see http://sourceforge.net/projects/libb64 */ #include const int CHARS_PER_LINE = 72; void base64_init_encodestate(base64_encodestate* state_in) { state_in->step = step_A; state_in->result = 0; state_in->stepcount = 0; } char base64_encode_value(char value_in) { static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; if (value_in > 63) return '='; return encoding[(int)value_in]; } int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in) { const char* plainchar = plaintext_in; const char* const plaintextend = plaintext_in + length_in; char* codechar = code_out; char result; char fragment; result = state_in->result; switch (state_in->step) { while (1) { case step_A: if (plainchar == plaintextend) { state_in->result = result; state_in->step = step_A; return codechar - code_out; } fragment = *plainchar++; result = (fragment & 0x0fc) >> 2; *codechar++ = base64_encode_value(result); result = (fragment & 0x003) << 4; case step_B: if (plainchar == plaintextend) { state_in->result = result; state_in->step = step_B; return codechar - code_out; } fragment = *plainchar++; result |= (fragment & 0x0f0) >> 4; *codechar++ = base64_encode_value(result); result = (fragment & 0x00f) << 2; case step_C: if (plainchar == plaintextend) { state_in->result = result; state_in->step = step_C; return codechar - code_out; } fragment = *plainchar++; result |= (fragment & 0x0c0) >> 6; *codechar++ = base64_encode_value(result); result = (fragment & 0x03f) >> 0; *codechar++ = base64_encode_value(result); ++(state_in->stepcount); if (state_in->stepcount == CHARS_PER_LINE/4) { *codechar++ = '\n'; state_in->stepcount = 0; } } } /* control should not reach here */ return codechar - code_out; } int base64_encode_blockend(char* code_out, base64_encodestate* state_in) { char* codechar = code_out; switch (state_in->step) { case step_B: *codechar++ = base64_encode_value(state_in->result); *codechar++ = '='; *codechar++ = '='; break; case step_C: *codechar++ = base64_encode_value(state_in->result); *codechar++ = '='; break; case step_A: break; } *codechar++ = '\n'; return codechar - code_out; } libminizinc-2.4.2/lib/chain_compressor.cpp000066400000000000000000000455541360574160400206610ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Jip J. Dekker */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include namespace MiniZinc { void ChainCompressor::removeItem(Item *i) { CollectDecls cd(env.vo, deletedVarDecls, i); if (auto ci = i->dyn_cast()) { topDown(cd, ci->e()); } else if (auto vdi = i->dyn_cast()) { topDown(cd, vdi->e()); } else { assert(false); // CURRENTLY NOT SUPPORTED } env.flat_removeItem(i); } int ChainCompressor::addItem(Item *i) { env.flat_addItem(i); int item_idx = env.flat()->size()-1; trackItem(i); return item_idx; } void ChainCompressor::updateCount() { for (auto it = this->items.begin(); it != items.end();) { if (it->second->removed()) { it = this->items.erase(it); } else { ++it; } } } void ChainCompressor::replaceCallArgument(Item *i, Call *c, unsigned int n, Expression *e) { CollectDecls cd(env.vo, deletedVarDecls, i); topDown(cd, c->arg(n)); c->arg(n, e); CollectOccurrencesE ce(env.vo, i); topDown(ce, e); } bool ImpCompressor::trackItem(Item *i) { if (i->removed()) { return false; } if (auto ci = i->dyn_cast()) { if (auto c = ci->e()->dyn_cast()) { // clause([y], [x]); i.e. x -> y if (c->id() == constants().ids.clause) { auto positive = c->arg(0)->cast(); auto negative = c->arg(1)->cast(); if (positive->length() == 1 && negative->length() == 1) { auto var = (*negative)[0]->cast(); storeItem(var->decl(), i); return true; } } else if (c->id() == "mzn_reverse_map_var") { auto control = c->arg(0)->cast(); assert(control->type().isvarbool()); storeItem(control->decl(), i); return true; // pred_imp(..., b); i.e. b -> pred(...) } else if (c->id().endsWith("_imp")) { auto control = c->arg(c->n_args()-1)->cast(); assert(control->type().isvarbool()); storeItem(control->decl(), i); return true; } } } else if (auto vdi = i->dyn_cast()) { if (vdi->e()->type().isvarbool() && vdi->e() && vdi->e()->e()) { if (auto c = vdi->e()->e()->dyn_cast()) { // x = forall([y,z,...]); potentially: x -> (y /\ z /\ ...) if (c->id() == constants().ids.forall) { storeItem(vdi->e(), i); return true; // x ::ctx_pos = pred(...); potentially: pred_imp(..., x); i.e. x -> pred(...) } else if (env.fopts.enable_imp && vdi->e()->ann().contains(constants().ctx.pos)) { GCLock lock; auto cid = env.halfReifyId(c->id()); std::vector args; args.reserve(c->n_args() +1); for (int j = 0; j < c->n_args(); ++j) { args.push_back(c->arg(j)->type()); } args.push_back(Type::varbool()); FunctionI* decl = env.model->matchFn(env,cid,args,false); if (decl) { storeItem(vdi->e(), i); return true; } } } } } return false; } void ImpCompressor::compress() { for (auto it = items.begin(); it != items.end();) { VarDecl *lhs = nullptr; VarDecl *rhs = nullptr; // Check if compression is possible if (auto ci = it->second->dyn_cast()) { auto c = ci->e()->cast(); if (c->id() == constants().ids.clause) { auto positive = c->arg(0)->cast(); auto var = (*positive)[0]->cast(); bool output_var = var->decl()->ann().contains(constants().ann.output_var); auto usages = env.vo.usages(var->decl()); output_var = output_var || usages.second; int occurrences = usages.first; unsigned long lhs_occurences = count(var->decl()); // Compress if: // - There is one occurrence on the RHS of a clause and the others are on the LHS of a clause // - There is one occurrence on the RHS of a clause, that Id is a reified forall that has no // other occurrences // - There is one occurrence on the RHS of a clause, that Id is a reification in a positive // context, and all other occurrences are on the LHS of a clause bool compress = !output_var && lhs_occurences > 0; if (var->decl()->e() && var->decl()->e()->dyn_cast()) { auto call = var->decl()->e()->cast(); if(call->id() == constants().ids.forall) { compress = compress && (occurrences == 1 && lhs_occurences == 1); } else { compress = compress && (occurrences == lhs_occurences); } } else { compress = compress && (occurrences == lhs_occurences + 1); } if (compress) { rhs = var->decl(); auto negative = c->arg(1)->cast(); lhs = (*negative)[0]->cast()->decl(); if (lhs == rhs) { continue; } } // TODO: Detect equivalences for output variables. } } if (lhs && rhs) { assert(count(rhs) > 0); auto range = find(rhs); for (auto match = range.first; match != range.second;) { bool succes = compressItem(match->second, lhs); assert(succes); env.n_imp_del++; match = items.erase(match); } assert(!rhs->ann().contains(constants().ann.output_var)); removeItem(it->second); it = items.erase(it); } else { ++it; } } } bool ImpCompressor::compressItem(Item *i, VarDecl *newLHS) { GCLock lock; if (auto ci = i->dyn_cast()) { auto c = ci->e()->cast(); // Given (x -> y) /\ (y -> z), produce x -> z if (c->id() == constants().ids.clause) { auto positive = c->arg(0)->cast(); auto rhs = (*positive)[0]->cast(); if (rhs->decl() != newLHS) { ConstraintI *nci = constructClause(positive, newLHS->id()); boolConstraints.push_back(addItem(nci)); } removeItem(i); return true; // Given (x -> y) /\ (y -> pred(...)), produce x -> pred(...) } else if (c->id() == "mzn_reverse_map_var") { return true; } else if (c->id().endsWith("_imp")) { replaceCallArgument(i, c, c->n_args()-1, newLHS->id()); trackItem(i); return true; } } else if (auto vdi = i->dyn_cast()) { auto c = vdi->e()->e()->dyn_cast(); // Given: (x -> y) /\ (y -> (a /\ b /\ ...)), produce (x -> a) /\ (x -> b) /\ ... if (c->id() == constants().ids.forall) { auto exprs = c->arg(0)->cast(); for (int j = 0; j < exprs->size(); ++j) { auto rhs = (*exprs)[j]->cast(); if (rhs->decl() != newLHS) { ConstraintI *nci = constructClause(rhs, newLHS->id()); boolConstraints.push_back(addItem(nci)); } } return true; // x ::ctx_pos = pred(...); potentially: pred_imp(..., x); i.e. x -> pred(...) } else if (vdi->e()->ann().contains(constants().ctx.pos)) { ConstraintI *nci = constructHalfReif(c, newLHS->id()); assert(nci); addItem(nci); return true; } } return false; } ConstraintI* ImpCompressor::constructClause(Expression *pos, Expression *neg) { assert(GC::locked()); std::vector args(2); if (pos->dyn_cast()) { args[0] = pos; } else { assert(neg->type().isbool()); std::vector eVec(1); eVec[0] = pos; args[0] = new ArrayLit(pos->loc().introduce(), eVec); args[0]->type(Type::varbool(1)); } if (neg->dyn_cast()) { args[1] = neg; } else { assert(neg->type().isbool()); std::vector eVec(1); eVec[0] = neg; args[1] = new ArrayLit(neg->loc().introduce(), eVec); args[1]->type(Type::varbool(1)); } // NEVER CREATE (a -> a) assert( (*args[0]->dyn_cast())[0]->dyn_cast()->decl() != (*args[1]->dyn_cast())[0]->dyn_cast()->decl()); auto nc = new Call(MiniZinc::Location().introduce(), constants().ids.clause, args); nc->type(Type::varbool()); nc->decl(env.model->matchFn(env, nc, false)); assert(nc->decl()); return new ConstraintI(MiniZinc::Location().introduce(), nc); } ConstraintI *ImpCompressor::constructHalfReif(Call *call, Id *control) { assert(env.fopts.enable_imp); assert(GC::locked()); auto cid = env.halfReifyId(call->id()); std::vector args(call->n_args()); for (int i = 0; i < call->n_args(); ++i) { args[i] = call->arg(i); } args.push_back(control); FunctionI* decl = env.model->matchFn(env, cid, args, false); if (decl) { auto nc = new Call(call->loc().introduce(), cid, args); nc->decl(decl); nc->type(Type::varbool()); return new ConstraintI(call->loc().introduce(), nc); } return nullptr; } bool LECompressor::trackItem(Item *i) { if (i->removed()) { return false; } bool added = false; if (auto ci = i->dyn_cast()) { if (auto call = ci->e()->dyn_cast()) { // {int,float}_lin_le([c1,c2,...], [x, y,...], 0); if (call->id() == constants().ids.int_.lin_le || call->id() == constants().ids.float_.lin_le) { auto as = follow_id(call->arg(0))->cast(); auto bs = follow_id(call->arg(1))->cast(); assert(as->size() == bs->size()); for (int j = 0; j < as->size(); ++j) { if (as->type().isintarray()) { if (follow_id((*as)[j])->cast()->v() > IntVal(0)) { // Check if left hand side is a variable (could be constant) if (auto decl = follow_id_to_decl((*bs)[j])->dyn_cast()) { storeItem(decl, i); added = true; } } } else { if (follow_id((*as)[j])->cast()->v() > FloatVal(0)) { // Check if left hand side is a variable (could be constant) if (auto decl = follow_id_to_decl((*bs)[j])->dyn_cast()) { storeItem(decl, i); added = true; } } } } } assert(call->id() != constants().ids.int2float); } } else if(auto vdi = i->dyn_cast()) { assert(vdi->e()); if (Expression* vde = vdi->e()->e()) { if (auto call = vde->dyn_cast()) { if (call->id() == constants().ids.int2float) { if (auto vd = follow_id_to_decl(call->arg(0))->dyn_cast()) { auto alias = follow_id_to_decl(vdi->e())->cast(); aliasMap[vd] = alias; } } } } } return added; } void LECompressor::compress() { for (auto it = items.begin(); it != items.end();) { VarDecl *lhs = nullptr; VarDecl *rhs = nullptr; VarDecl *alias = nullptr; // Check if compression is possible if (auto ci = it->second->dyn_cast()) { auto call = ci->e()->cast(); if (call->id() == constants().ids.int_.lin_le) { auto as = follow_id(call->arg(0))->cast(); auto bs = follow_id(call->arg(1))->cast(); auto c = follow_id(call->arg(2))->cast(); if (bs->size() == 2 && c->v() == IntVal(0)) { auto a0 = follow_id((*as)[0])->cast()->v(); auto a1 = follow_id((*as)[1])->cast()->v(); if (a0 == -a1 && eqBounds((*bs)[0], (*bs)[1])) { int i = a0 < a1 ? 0 : 1; if (!(*bs)[i]->isa()) { break; } auto neg = follow_id_to_decl((*bs)[i])->cast(); bool output_var = neg->ann().contains(constants().ann.output_var); auto usages = env.vo.usages(neg); int occurrences = usages.first; output_var = output_var || usages.second; unsigned long lhs_occurences = count(neg); bool compress = !output_var; auto search = aliasMap.find(neg); if (search != aliasMap.end()) { alias = search->second; auto alias_usages = env.vo.usages(alias); int alias_occ = alias_usages.first; compress = compress && (!alias_usages.second); unsigned long alias_lhs_occ = count(alias); // neg is only allowed to occur: // - once in the "implication" // - once in the aliasing // - on a lhs of other expressions // alias is only allowed to occur on a lhs of an expression. compress = compress && (lhs_occurences + alias_lhs_occ > 0) && (occurrences == lhs_occurences + 2) && (alias_occ == alias_lhs_occ); } else { // neg is only allowed to occur: // - once in the "implication" // - on a lhs of other expressions compress = compress && (lhs_occurences > 0) && (occurrences == lhs_occurences + 1); } auto pos = follow_id_to_decl((*bs)[1 - i])->dyn_cast(); if (pos && compress) { rhs = neg; lhs = pos; assert(lhs != rhs); } // TODO: Detect equivalences for output variables. } } } } if(lhs && rhs) { assert(count(rhs) + count(alias) > 0); auto range = find(rhs); for (auto match = range.first; match != range.second;) { LEReplaceVar(match->second, rhs, lhs); match = items.erase(match); } if (alias) { VarDecl* i2f_lhs; auto search = aliasMap.find(lhs); if (search != aliasMap.end()) { i2f_lhs = search->second; } else { // Create new int2float Call* i2f = new Call(lhs->loc().introduce(), constants().ids.int2float, {lhs->id()}); i2f->decl(env.model->matchFn(env, i2f, false)); assert(i2f->decl()); i2f->type(Type::varfloat()); auto domain = new SetLit(lhs->loc().introduce(), eval_floatset(env, lhs->ti()->domain())); auto i2f_ti = new TypeInst(lhs->loc().introduce(), Type::varfloat(), domain); i2f_lhs = new VarDecl(lhs->loc().introduce(), i2f_ti, env.genId(),i2f); i2f_lhs->type(Type::varfloat()); addItem(new VarDeclI(lhs->loc().introduce(), i2f_lhs)); } auto arange = find(alias); for (auto match = arange.first; match != arange.second;) { LEReplaceVar(match->second, alias, i2f_lhs); match = items.erase(match); } } assert(!rhs->ann().contains(constants().ann.output_var)); removeItem(it->second); env.n_lin_del++; it = items.erase(it); } else { ++it; } } } template void LECompressor::LEReplaceVar(Item *i, VarDecl *oldVar, VarDecl *newVar) { typedef typename LinearTraits::Val Val; GCLock lock; auto ci = i->cast(); auto call = ci->e()->cast(); assert(call->id() == constants().ids.int_.lin_le || call->id() == constants().ids.float_.lin_le); // Remove old occurrences CollectDecls cd(env.vo, deletedVarDecls, i); topDown(cd, ci->e()); ArrayLit* al_c = eval_array_lit(env, call->arg(0)); std::vector coeffs(al_c->size()); for (int j = 0; j < al_c->size(); j++) { coeffs[j] = LinearTraits::eval(env, (*al_c)[j]); } ArrayLit* al_x = eval_array_lit(env, call->arg(1)); std::vector x(al_x->size()); for (int j = 0; j < al_x->size(); j++) { Expression* decl = follow_id_to_decl((*al_x)[j]); if (decl && decl->cast() == oldVar) { x[j] = newVar->id(); } else { x[j] = (*al_x)[j]; } } Val d = LinearTraits::eval(env, call->arg(2)); simplify_lin(coeffs, x, d); if (coeffs.empty()) { env.flat_removeItem(i); env.n_lin_del++; return; } else { std::vector coeffs_e(coeffs.size()); std::vector x_e(coeffs.size()); for (unsigned int j = 0; j < coeffs.size(); j++) { coeffs_e[j] = Lit::a(coeffs[j]); x_e[j] = x[j](); Expression* decl = follow_id_to_decl(x_e[j]); if (decl && decl->cast() == newVar) { storeItem(newVar, i); } } if (auto arg0 = call->arg(0)->dyn_cast()) { arg0->setVec(coeffs_e); } else { auto al_c_new = new ArrayLit(al_c->loc().introduce(),coeffs_e); al_c_new->type(al_c->type()); call->arg(0, al_c_new); } if (auto arg1 = call->arg(1)->dyn_cast()) { arg1->setVec(x_e); } else { auto al_x_new = new ArrayLit(al_x->loc().introduce(),x_e); al_x_new->type(al_x->type()); call->arg(1, al_x_new); } call->arg(2, Lit::a(d)); } // Add new occurences CollectOccurrencesE ce(env.vo, i); topDown(ce, ci->e()); } bool LECompressor::eqBounds(Expression *a, Expression *b) { // TODO: (To optimise) Check lb(lhs) >= lb(rhs) and enforce ub(lhs) <= ub(rhs) IntSetVal* dom_a = nullptr; IntSetVal* dom_b = nullptr; if(auto a_decl = follow_id_to_decl(a)->dyn_cast()) { if (a_decl->ti()->domain()) { dom_a = eval_intset(env, a_decl->ti()->domain()); } } else { assert(a->dyn_cast()); auto a_val = a->cast(); dom_a = IntSetVal::a(a_val->v(), a_val->v()); } if(auto b_decl = follow_id_to_decl(b)->dyn_cast()) { if (b_decl->ti()->domain()) { dom_b = eval_intset(env, b_decl->ti()->domain()); } } else { assert(b->dyn_cast()); auto b_val = b->cast(); dom_b = IntSetVal::a(b_val->v(), b_val->v()); } return (dom_a && dom_b && (dom_a->min() == dom_b->min()) && (dom_a->max() == dom_b->max())) || (!dom_a && !dom_b); } } libminizinc-2.4.2/lib/copy.cpp000066400000000000000000000454011360574160400162640ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include namespace MiniZinc { void CopyMap::insert(Expression* e0, Expression* e1) { if (!e0->isUnboxedVal() && !e1->isUnboxedVal()) node_m.insert(e0,e1); } Expression* CopyMap::find(Expression* e) { return static_cast(node_m.find(e)); } void CopyMap::insert(Item* e0, Item* e1) { node_m.insert(e0,e1); } Item* CopyMap::find(Item* e) { return static_cast(node_m.find(e)); } void CopyMap::insert(Model* e0, Model* e1) { model_m.insert(std::make_pair(e0,e1)); } Model* CopyMap::find(Model* e) { ModelMap::iterator it = model_m.find(e); if (it==model_m.end()) return NULL; return it->second; } void CopyMap::insert(const ASTString& e0, const ASTString& e1) { node_m.insert(e0.aststr(),e1.aststr()); } ASTStringO* CopyMap::find(const ASTString& e) { return static_cast(node_m.find(e.aststr())); } void CopyMap::insert(IntSetVal* e0, IntSetVal* e1) { node_m.insert(e0,e1); } IntSetVal* CopyMap::find(IntSetVal* e) { return static_cast(node_m.find(e)); } void CopyMap::insert(FloatSetVal* e0, FloatSetVal* e1) { node_m.insert(e0,e1); } FloatSetVal* CopyMap::find(FloatSetVal* e) { return static_cast(node_m.find(e)); } Location copy_location(CopyMap& m, const Location& _loc) { return _loc; } Location copy_location(CopyMap& m, Expression* e) { return copy_location(m,e->loc()); } Location copy_location(CopyMap& m, Item* i) { return copy_location(m,i->loc()); } void copy_ann(EnvI& env, CopyMap& m, Annotation& oldAnn, Annotation& newAnn, bool followIds, bool copyFundecls, bool isFlatModel); Expression* copy(EnvI& env, CopyMap& m, Expression* e, bool followIds, bool copyFundecls, bool isFlatModel) { if (e==NULL) return NULL; if (Expression* cached = m.find(e)) return cached; Expression* ret = NULL; switch (e->eid()) { case Expression::E_INTLIT: { IntLit* c = IntLit::a(e->cast()->v()); m.insert(e,c); ret = c; } break; case Expression::E_FLOATLIT: { FloatLit* c = FloatLit::a(e->cast()->v()); m.insert(e,c); ret = c; } break; case Expression::E_SETLIT: { SetLit* s = e->cast(); SetLit* c = new SetLit(copy_location(m,e),static_cast(NULL)); m.insert(e,c); if (s->isv()) { IntSetVal* isv; if (IntSetVal* isvc = m.find(s->isv())) { isv = isvc; } else { IntSetRanges r(s->isv()); isv = IntSetVal::ai(r); m.insert(s->isv(),isv); } c->isv(isv); } else if (s->fsv()) { FloatSetVal* fsv; if (FloatSetVal* fsvc = m.find(s->fsv())) { fsv = fsvc; } else { FloatSetRanges r(s->fsv()); fsv = FloatSetVal::ai(r); m.insert(s->fsv(),fsv); } c->fsv(fsv); } else { if (ASTExprVecO* ve = m.find(s->v())) { c->v(ASTExprVec(ve)); } else { std::vector elems(s->v().size()); for (unsigned int i=s->v().size(); i--;) elems[i] = copy(env,m,s->v()[i],followIds,copyFundecls,isFlatModel); ASTExprVec ce(elems); m.insert(s->v(),ce); c->v(ce); } } ret = c; } break; case Expression::E_BOOLLIT: { ret = e; } break; case Expression::E_STRINGLIT: { StringLit* sl = e->cast(); StringLit* c; if (ASTStringO* cs = m.find(sl->v())) { c = new StringLit(copy_location(m,e),ASTString(cs)); } else { ASTString s(sl->v().str()); m.insert(sl->v(),s); c = new StringLit(copy_location(m,e),s); } m.insert(e,c); ret = c; } break; case Expression::E_ID: { if (e==constants().absent) return e; Id* id = e->cast(); if (followIds) { Id* prevId = id; Expression* cur = e; bool done = false; do { if (cur==NULL) { cur = prevId; done = true; } else { switch (cur->eid()) { case Expression::E_ID: prevId = cur->cast(); cur = prevId->decl(); break; case Expression::E_VARDECL: if (cur->cast()->e()) { cur = cur->cast()->e(); } else { cur = prevId; done = true; } break; default: done = true; } } } while (!done); if (cur->isa()) { return cur; } else { return copy(env,m,cur,false); } } else { Id* c; if (id->decl()) { VarDecl* vd = static_cast(copy(env,m,id->decl(),followIds,copyFundecls,isFlatModel)); c = vd->id(); } else { if (id->idn()!=-1) { c = new Id(copy_location(m,e),id->idn(),NULL); } else { ASTString id_v; if (ASTStringO* cs = m.find(id->v())) { id_v = ASTString(cs); } else { id_v = ASTString(id->v().str()); m.insert(id->v(),id_v); } c = new Id(copy_location(m,e),id_v,NULL); } } m.insert(e,c); ret = c; } } break; case Expression::E_ANON: { AnonVar* c = new AnonVar(copy_location(m,e)); m.insert(e,c); ret = c; } break; case Expression::E_ARRAYLIT: { ArrayLit* al = e->cast(); std::vector > dims(al->dims()); for (unsigned int i=0; imin(i); dims[i].second = al->max(i); } if (ArrayLit* sliceView = al->getSliceLiteral()) { ASTIntVec dimsInternal = al->dimsInternal(); int sliceDims = sliceView->dims(); int dimsOffset = al->dims()*2; std::vector> slice(sliceDims); for (int i=0; icast(),dims,slice); m.insert(e,c); ret = c; } else { ArrayLit* c = new ArrayLit(copy_location(m,e),std::vector(),dims); m.insert(e,c); ASTExprVecO* v; if (ASTExprVecO* cv = m.find(al->getVec())) { v = cv; } else { std::vector elems(al->size()); for (unsigned int i=al->size(); i--;) elems[i] = copy(env,m,(*al)[i],followIds,copyFundecls,isFlatModel); ASTExprVec ce(elems); m.insert(al->getVec(),ce); v = ce.vec(); } c->setVec(ASTExprVec(v)); ret = c; } } break; case Expression::E_ARRAYACCESS: { ArrayAccess* aa = e->cast(); ArrayAccess* c = new ArrayAccess(copy_location(m,e),NULL,std::vector()); m.insert(e,c); ASTExprVecO* idx; if (ASTExprVecO* cidx = m.find(aa->idx())) { idx = cidx; } else { std::vector elems(aa->idx().size()); for (unsigned int i=aa->idx().size(); i--;) elems[i] = copy(env,m,aa->idx()[i],followIds,copyFundecls,isFlatModel); ASTExprVec ce(elems); m.insert(aa->idx(),ce); idx = ce.vec(); } c->v(copy(env,m,aa->v(),followIds,copyFundecls,isFlatModel)); c->idx(ASTExprVec(idx)); ret = c; } break; case Expression::E_COMP: { Comprehension* c = e->cast(); Generators g; Comprehension* cc = new Comprehension(copy_location(m,e),NULL,g,c->set()); m.insert(c,cc); for (int i=0; in_generators(); i++) { std::vector vv; for (int j=0; jn_decls(i); j++) vv.push_back(static_cast(copy(env,m,c->decl(i,j),followIds,copyFundecls,isFlatModel))); g._g.push_back(Generator(vv,copy(env,m,c->in(i),followIds,copyFundecls,isFlatModel), copy(env,m,c->where(i),followIds,copyFundecls,isFlatModel))); } cc->init(copy(env,m,c->e(),followIds,copyFundecls,isFlatModel),g); ret = cc; } break; case Expression::E_ITE: { ITE* ite = e->cast(); ITE* c = new ITE(copy_location(m,e),std::vector(),NULL); m.insert(e,c); std::vector ifthen(2*ite->size()); for (unsigned int i=ite->size(); i--;) { ifthen[2*i] = copy(env,m,ite->e_if(i),followIds,copyFundecls,isFlatModel); ifthen[2*i+1] = copy(env,m,ite->e_then(i),followIds,copyFundecls,isFlatModel); } c->init(ifthen,copy(env,m,ite->e_else(),followIds,copyFundecls,isFlatModel)); ret = c; } break; case Expression::E_BINOP: { BinOp* b = e->cast(); BinOp* c = new BinOp(copy_location(m,e),NULL,b->op(),NULL); m.insert(e,c); c->lhs(copy(env,m,b->lhs(),followIds,copyFundecls,isFlatModel)); c->rhs(copy(env,m,b->rhs(),followIds,copyFundecls,isFlatModel)); ret = c; } break; case Expression::E_UNOP: { UnOp* b = e->cast(); UnOp* c = new UnOp(copy_location(m,e),b->op(),NULL); m.insert(e,c); c->e(copy(env,m,b->e(),followIds,copyFundecls,isFlatModel)); ret = c; } break; case Expression::E_CALL: { Call* ca = e->cast(); ASTString id_v; if (ASTStringO* cs = m.find(ca->id())) { id_v = ASTString(cs); } else { id_v = ASTString(ca->id().str()); m.insert(ca->id(),id_v); } Call* c = new Call(copy_location(m,e),id_v,std::vector()); if (ca->decl()) { if (copyFundecls) { c->decl(Item::cast(copy(env,m,ca->decl()))); } else { c->decl(ca->decl()); } } m.insert(e,c); std::vector args(ca->n_args()); for (unsigned int i=static_cast(args.size()); i--;) args[i] = copy(env,m,ca->arg(i),followIds,copyFundecls,isFlatModel); c->args(args); ret = c; } break; case Expression::E_VARDECL: { VarDecl* vd = e->cast(); VarDecl* c; if (vd->id()->idn()==-1) { ASTString id_v; if (ASTStringO* cs = m.find(vd->id()->v())) { id_v = ASTString(cs); } else { id_v = ASTString(vd->id()->v().str()); m.insert(vd->id()->v(),id_v); } c = new VarDecl(copy_location(m,e),NULL,id_v,NULL); } else { c = new VarDecl(copy_location(m,e),NULL,vd->id()->idn(),NULL); } c->toplevel(vd->toplevel()); c->introduced(vd->introduced()); if (isFlatModel && vd->flat()==vd) c->flat(c); else c->flat(vd->flat()); c->payload(vd->payload()); m.insert(e,c); m.insert(c,c); c->ti(static_cast(copy(env,m,vd->ti(),followIds,copyFundecls,isFlatModel))); c->e(copy(env,m,vd->e(),followIds,copyFundecls,isFlatModel)); c->type(c->ti()->type()); c->id()->type(c->type()); ret = c; } break; case Expression::E_LET: { Let* l = e->cast(); std::vector let(l->let().size()); for (unsigned int i=l->let().size(); i--;) let[i] = copy(env,m,l->let()[i],followIds,copyFundecls,isFlatModel); Let* c = new Let(copy_location(m,e),let,copy(env,m,l->in(),followIds,copyFundecls,isFlatModel)); for (unsigned int i=l->_let_orig.size(); i--;) { c->_let_orig[i] = copy(env,m,l->_let_orig[i],followIds,copyFundecls,isFlatModel); } m.insert(e,c); ret = c; } break; case Expression::E_TI: { TypeInst* t = e->cast(); ASTExprVecO* r; if (t->ranges().size()==0) { r = NULL; } else if (ASTExprVecO* cr = m.find(t->ranges())) { r = cr; } else { std::vector rr(t->ranges().size()); for (unsigned int i=t->ranges().size(); i--;) rr[i] = static_cast(copy(env,m,t->ranges()[i],followIds,copyFundecls,isFlatModel)); r = ASTExprVecO::a(rr); } TypeInst* c = new TypeInst(copy_location(m,e),t->type(), ASTExprVec(r),copy(env,m,t->domain(),followIds,copyFundecls,isFlatModel)); c->setIsEnum(t->isEnum()); m.insert(e,c); ret = c; } break; case Expression::E_TIID: { TIId* t = e->cast(); TIId* c = new TIId(copy_location(m,e),t->v().str()); m.insert(e,c); ret = c; } break; default: assert(false); } if (!ret->isa() || ret->cast()->decl()==NULL) ret->type(e->type()); copy_ann(env,m,e->ann(),ret->ann(),followIds,copyFundecls,isFlatModel); return ret; } void copy_ann(EnvI& env, CopyMap& m, Annotation& oldAnn, Annotation& newAnn, bool followIds, bool copyFundecls, bool isFlatModel) { for (ExpressionSetIter it = oldAnn.begin(); it != oldAnn.end(); ++it) newAnn.add(copy(env,m,*it,followIds,copyFundecls,isFlatModel)); } Expression* copy(EnvI& env, Expression* e, bool followIds, bool copyFundecls, bool isFlatModel) { CopyMap m; return copy(env,m,e,followIds,copyFundecls,isFlatModel); } Model* copy(EnvI& env, CopyMap& cm, Model* m, bool isFlatModel); Item* copy(EnvI& env, CopyMap& m, Item* i, bool followIds, bool copyFundecls, bool isFlatModel) { if (i==NULL) return NULL; if (Item* cached = m.find(i)) return cached; switch (i->iid()) { case Item::II_INC: { IncludeI* ii = i->cast(); IncludeI* c = new IncludeI(copy_location(m,i), ASTString(ii->f().str())); m.insert(i,c); c->m(copy(env,m,ii->m()),ii->own()); return c; } case Item::II_VD: { VarDeclI* v = i->cast(); VarDeclI* c = new VarDeclI(copy_location(m,i), NULL); m.insert(i,c); c->e(static_cast(copy(env,m,v->e(),followIds,copyFundecls,isFlatModel))); return c; } case Item::II_ASN: { AssignI* a = i->cast(); AssignI* c = new AssignI(copy_location(m,i), a->id().str(),NULL); m.insert(i,c); c->e(copy(env,m,a->e(),followIds,copyFundecls,isFlatModel)); c->decl(static_cast(copy(env,m,a->decl(),followIds,copyFundecls,isFlatModel))); return c; } case Item::II_CON: { ConstraintI* cc = i->cast(); ConstraintI* c = new ConstraintI(copy_location(m,i),NULL); m.insert(i,c); c->e(copy(env,m,cc->e(),followIds,copyFundecls,isFlatModel)); return c; } case Item::II_SOL: { SolveI* s = i->cast(); SolveI* c; switch (s->st()) { case SolveI::ST_SAT: c = SolveI::sat(Location()); break; case SolveI::ST_MIN: c = SolveI::min(Location(),copy(env,m,s->e(),followIds,copyFundecls,isFlatModel)); break; case SolveI::ST_MAX: c = SolveI::max(Location(),copy(env,m,s->e(),followIds,copyFundecls,isFlatModel)); break; } copy_ann(env,m, s->ann(), c->ann(), followIds,copyFundecls,isFlatModel); m.insert(i,c); return c; } case Item::II_OUT: { OutputI* o = i->cast(); OutputI* c = new OutputI(copy_location(m,i),copy(env,m,o->e(),followIds,copyFundecls,isFlatModel)); m.insert(i,c); return c; } case Item::II_FUN: { FunctionI* f = i->cast(); std::vector params(f->params().size()); for (unsigned int j=f->params().size(); j--;) params[j] = static_cast(copy(env,m,f->params()[j],followIds,copyFundecls,isFlatModel)); FunctionI* c = new FunctionI(copy_location(m,i),f->id().str(), static_cast(copy(env,m,f->ti(),followIds,copyFundecls,isFlatModel)), params, copy(env,m,f->e(),followIds,copyFundecls,isFlatModel)); c->_builtins.e = f->_builtins.e; c->_builtins.i = f->_builtins.i; c->_builtins.f = f->_builtins.f; c->_builtins.b = f->_builtins.b; c->_builtins.s = f->_builtins.s; c->_builtins.str = f->_builtins.str; copy_ann(env,m, f->ann(), c->ann(), followIds,copyFundecls,isFlatModel); m.insert(i,c); return c; } default: assert(false); return NULL; } } Item* copy(EnvI& env, Item* i, bool followIds, bool copyFundecls, bool isFlatModel) { CopyMap m; return copy(env,m,i,followIds,copyFundecls,isFlatModel); } Model* copy(EnvI& env, CopyMap& cm, Model* m, bool isFlatModel) { if (m==NULL) return NULL; if (Model* cached = cm.find(m)) return cached; Model* c = new Model; for (unsigned int i=0; isize(); i++) c->addItem(copy(env,cm,(*m)[i],false,true)); for (Model::FnMap::iterator it = m->fnmap.begin(); it != m->fnmap.end(); ++it) { for (unsigned int i=0; isecond.size(); i++) c->registerFn(env,copy(env,cm,it->second[i].fi,false,true,isFlatModel)->cast()); } cm.insert(m,c); return c; } Model* copy(EnvI& env, Model* m) { CopyMap cm; return copy(env,cm,m); } } libminizinc-2.4.2/lib/eval_par.cpp000066400000000000000000003245651360574160400171160ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include #include #include namespace MiniZinc { bool checkParDomain(EnvI& env, Expression* e, Expression* domain) { if (e->type()==Type::parint()) { IntSetVal* isv = eval_intset(env,domain); if (!isv->contains(eval_int(env,e))) return false; } else if (e->type()==Type::parfloat()) { FloatSetVal* fsv = eval_floatset(env,domain); if (!fsv->contains(eval_float(env, e))) return false; } else if (e->type()==Type::parsetint()) { IntSetVal* isv = eval_intset(env,domain); IntSetRanges ir(isv); IntSetVal* rsv = eval_intset(env,e); IntSetRanges rr(rsv); if (!Ranges::subset(rr, ir)) return false; } else if (e->type()==Type::parsetfloat()) { FloatSetVal* fsv = eval_floatset(env,domain); FloatSetRanges fr(fsv); FloatSetVal* rsv = eval_floatset(env,e); FloatSetRanges rr(rsv); if (!Ranges::subset(rr, fr)) return false; } return true; } template typename E::Val eval_id(EnvI& env, Expression* e) { Id* id = e->cast(); if (id->decl() == NULL) throw EvalError(env, e->loc(), "undeclared identifier", id->str().str()); VarDecl* vd = id->decl(); while (vd->flat() && vd->flat() != vd) vd = vd->flat(); if (vd->e() == NULL) throw EvalError(env, vd->loc(), "cannot evaluate expression", id->str().str()); typename E::Val r = E::e(env,vd->e()); if (!vd->evaluated() && (vd->toplevel() || vd->type().dim() > 0) ) { Expression* ne = E::exp(r); vd->e(ne); vd->evaluated(true); } return r; } class EvalIntLit { public: typedef IntLit* Val; typedef Expression* ArrayVal; static IntLit* e(EnvI& env, Expression* e) { return IntLit::a(eval_int(env, e)); } static Expression* exp(IntLit* e) { return e; } Expression* flatten(EnvI&, Expression*) { throw InternalError("evaluating var assignment generator inside par expression not supported"); } }; class EvalIntVal { public: typedef IntVal Val; typedef IntVal ArrayVal; static IntVal e(EnvI& env, Expression* e) { return eval_int(env, e); } static Expression* exp(IntVal e) { return IntLit::a(e); } static void checkRetVal(EnvI& env, Val v, FunctionI* fi) { if (fi->ti()->domain() && !fi->ti()->domain()->isa()) { IntSetVal* isv = eval_intset(env, fi->ti()->domain()); if (!isv->contains(v)) { throw ResultUndefinedError(env, Location().introduce(), "function result violates function type-inst"); } } } Expression* flatten(EnvI&, Expression*) { throw InternalError("evaluating var assignment generator inside par expression not supported"); } }; class EvalFloatVal { public: typedef FloatVal Val; typedef FloatVal ArrayVal; static FloatVal e(EnvI& env, Expression* e) { return eval_float(env, e); } static Expression* exp(FloatVal e) { return FloatLit::a(e); } static void checkRetVal(EnvI& env, Val v, FunctionI* fi) { if (fi->ti()->domain() && !fi->ti()->domain()->isa()) { FloatSetVal* fsv = eval_floatset(env, fi->ti()->domain()); if (!fsv->contains(v)) { throw ResultUndefinedError(env, Location().introduce(), "function result violates function type-inst"); } } } Expression* flatten(EnvI&, Expression*) { throw InternalError("evaluating var assignment generator inside par expression not supported"); } }; class EvalFloatLit { public: typedef FloatLit* Val; typedef Expression* ArrayVal; static FloatLit* e(EnvI& env, Expression* e) { return FloatLit::a(eval_float(env, e)); } static Expression* exp(Expression* e) { return e; } Expression* flatten(EnvI&, Expression*) { throw InternalError("evaluating var assignment generator inside par expression not supported"); } }; class EvalString { public: typedef std::string Val; typedef std::string ArrayVal; static std::string e(EnvI& env, Expression* e) { return eval_string(env, e); } static Expression* exp(const std::string& e) { return new StringLit(Location(),e); } static void checkRetVal(EnvI& env, Val v, FunctionI* fi) { } Expression* flatten(EnvI&, Expression*) { throw InternalError("evaluating var assignment generator inside par expression not supported"); } }; class EvalStringLit { public: typedef StringLit* Val; typedef Expression* ArrayVal; static StringLit* e(EnvI& env, Expression* e) { return new StringLit(Location(),eval_string(env, e)); } static Expression* exp(Expression* e) { return e; } Expression* flatten(EnvI&, Expression*) { throw InternalError("evaluating var assignment generator inside par expression not supported"); } }; class EvalBoolLit { public: typedef BoolLit* Val; typedef Expression* ArrayVal; static BoolLit* e(EnvI& env, Expression* e) { return constants().boollit(eval_bool(env, e)); } static Expression* exp(Expression* e) { return e; } Expression* flatten(EnvI&, Expression*) { throw InternalError("evaluating var assignment generator inside par expression not supported"); } }; class EvalBoolVal { public: typedef bool Val; static bool e(EnvI& env, Expression* e) { return eval_bool(env, e); } static Expression* exp(bool e) { return constants().boollit(e); } static void checkRetVal(EnvI& env, Val v, FunctionI* fi) { } Expression* flatten(EnvI&, Expression*) { throw InternalError("evaluating var assignment generator inside par expression not supported"); } }; class EvalArrayLit { public: typedef ArrayLit* Val; typedef Expression* ArrayVal; static ArrayLit* e(EnvI& env, Expression* e) { return eval_array_lit(env, e); } static Expression* exp(Expression* e) { return e; } Expression* flatten(EnvI&, Expression*) { throw InternalError("evaluating var assignment generator inside par expression not supported"); } }; class EvalArrayLitCopy { public: typedef ArrayLit* Val; typedef Expression* ArrayVal; static ArrayLit* e(EnvI& env, Expression* e) { return copy(env,eval_array_lit(env, e),true)->cast(); } static Expression* exp(Expression* e) { return e; } static void checkRetVal(EnvI& env, Val v, FunctionI* fi) { for (unsigned int i=0; iti()->ranges().size(); i++) { if (fi->ti()->ranges()[i]->domain() && !fi->ti()->ranges()[i]->domain()->isa()) { IntSetVal* isv = eval_intset(env, fi->ti()->ranges()[i]->domain()); bool bothEmpty = isv->min() > isv->max() && v->min(i) > v->max(i); if (!bothEmpty && (v->min(i) != isv->min() || v->max(i) != isv->max())) { std::ostringstream oss; oss << "array index set " << (i+1) << " of function result violates function type-inst"; throw ResultUndefinedError(env, fi->e()->loc(), oss.str()); } } } if (fi->ti()->domain() && !fi->ti()->domain()->isa() && fi->ti()->type().ti()==Type::TI_PAR) { Type base_t = fi->ti()->type(); if (base_t.bt() == Type::BT_INT) { IntSetVal* isv = eval_intset(env, fi->ti()->domain()); if (base_t.st() == Type::ST_PLAIN) { for (unsigned int i=0; isize(); i++) { IntVal iv = eval_int(env, (*v)[i]); if (!isv->contains(iv)) { std::ostringstream oss; oss << "array contains value " << iv << " which is not contained in " << *isv; throw ResultUndefinedError(env, fi->e()->loc(), "function result violates function type-inst, "+oss.str()); } } } else { for (unsigned int i=0; isize(); i++) { IntSetVal* iv = eval_intset(env, (*v)[i]); IntSetRanges isv_r(isv); IntSetRanges v_r(iv); if (!Ranges::subset(v_r, isv_r)) { std::ostringstream oss; oss << "array contains value " << *iv << " which is not a subset of " << *isv; throw ResultUndefinedError(env, fi->e()->loc(), "function result violates function type-inst, "+oss.str()); } } } } else if (base_t.bt() == Type::BT_FLOAT) { FloatSetVal* fsv = eval_floatset(env, fi->ti()->domain()); if (base_t.st() == Type::ST_PLAIN) { for (unsigned int i=0; isize(); i++) { FloatVal fv = eval_float(env, (*v)[i]); if (!fsv->contains(fv)) { std::ostringstream oss; oss << "array contains value " << fv << " which is not contained in " << *fsv; throw ResultUndefinedError(env, fi->e()->loc(), "function result violates function type-inst, "+oss.str()); } } } else { for (unsigned int i=0; isize(); i++) { FloatSetVal* fv = eval_floatset(env, (*v)[i]); FloatSetRanges fsv_r(fsv); FloatSetRanges v_r(fv); if (!Ranges::subset(v_r, fsv_r)) { std::ostringstream oss; oss << "array contains value " << *fv << " which is not a subset of " << *fsv; throw ResultUndefinedError(env, fi->e()->loc(), "function result violates function type-inst, "+oss.str()); } } } } } } Expression* flatten(EnvI&, Expression*) { throw InternalError("evaluating var assignment generator inside par expression not supported"); } }; class EvalIntSet { public: typedef IntSetVal* Val; static IntSetVal* e(EnvI& env, Expression* e) { return eval_intset(env, e); } static Expression* exp(IntSetVal* e) { return new SetLit(Location(),e); } static void checkRetVal(EnvI& env, Val v, FunctionI* fi) { if (fi->ti()->domain() && !fi->ti()->domain()->isa()) { IntSetVal* isv = eval_intset(env, fi->ti()->domain()); IntSetRanges isv_r(isv); IntSetRanges v_r(v); if (!Ranges::subset(v_r, isv_r)) { throw ResultUndefinedError(env, Location().introduce(), "function result violates function type-inst"); } } } Expression* flatten(EnvI&, Expression*) { throw InternalError("evaluating var assignment generator inside par expression not supported"); } }; class EvalFloatSet { public: typedef FloatSetVal* Val; static FloatSetVal* e(EnvI& env, Expression* e) { return eval_floatset(env, e); } static Expression* exp(FloatSetVal* e) { return new SetLit(Location(),e); } static void checkRetVal(EnvI& env, Val v, FunctionI* fi) { if (fi->ti()->domain() && !fi->ti()->domain()->isa()) { FloatSetVal* fsv = eval_floatset(env, fi->ti()->domain()); FloatSetRanges fsv_r(fsv); FloatSetRanges v_r(v); if (!Ranges::subset(v_r, fsv_r)) { throw ResultUndefinedError(env, Location().introduce(), "function result violates function type-inst"); } } } Expression* flatten(EnvI&, Expression*) { throw InternalError("evaluating var assignment generator inside par expression not supported"); } }; class EvalBoolSet { public: typedef IntSetVal* Val; static IntSetVal* e(EnvI& env, Expression* e) { return eval_boolset(env, e); } static Expression* exp(IntSetVal* e) { return new SetLit(Location(),e); } static void checkRetVal(EnvI& env, Val v, FunctionI* fi) { } Expression* flatten(EnvI&, Expression*) { throw InternalError("evaluating var assignment generator inside par expression not supported"); } }; class EvalSetLit { public: typedef SetLit* Val; typedef Expression* ArrayVal; static SetLit* e(EnvI& env, Expression* e) { switch (e->type().bt()) { case Type::BT_INT: case Type::BT_BOT: return new SetLit(e->loc(),eval_intset(env, e)); case Type::BT_BOOL: return new SetLit(e->loc(),eval_boolset(env, e)); case Type::BT_FLOAT: return new SetLit(e->loc(),eval_floatset(env, e)); default: throw InternalError("invalid set literal type"); } } static Expression* exp(Expression* e) { return e; } Expression* flatten(EnvI&, Expression*) { throw InternalError("evaluating var assignment generator inside par expression not supported"); } }; class EvalFloatSetLit { public: typedef SetLit* Val; typedef Expression* ArrayVal; static SetLit* e(EnvI& env, Expression* e) { return new SetLit(e->loc(),eval_floatset(env, e)); } static Expression* exp(Expression* e) { return e; } Expression* flatten(EnvI&, Expression*) { throw InternalError("evaluating var assignment generator inside par expression not supported"); } }; class EvalBoolSetLit { public: typedef SetLit* Val; typedef Expression* ArrayVal; static SetLit* e(EnvI& env, Expression* e) { return new SetLit(e->loc(),eval_boolset(env, e)); } static Expression* exp(Expression* e) { return e; } Expression* flatten(EnvI&, Expression*) { throw InternalError("evaluating var assignment generator inside par expression not supported"); } }; class EvalCopy { public: typedef Expression* Val; typedef Expression* ArrayVal; static Expression* e(EnvI& env, Expression* e) { return copy(env,e,true); } static Expression* exp(Expression* e) { return e; } Expression* flatten(EnvI&, Expression*) { throw InternalError("evaluating var assignment generator inside par expression not supported"); } }; class EvalPar { public: typedef Expression* Val; typedef Expression* ArrayVal; static Expression* e(EnvI& env, Expression* e) { return eval_par(env, e); } static Expression* exp(Expression* e) { return e; } static void checkRetVal(EnvI& env, Val v, FunctionI* fi) { } Expression* flatten(EnvI&, Expression*) { throw InternalError("evaluating var assignment generator inside par expression not supported"); } }; void checkDom(EnvI& env, Id* arg, IntSetVal* dom, Expression* e) { bool oob = false; if (!e->type().isopt()) { if (e->type().isintset()) { IntSetVal* ev = eval_intset(env, e); IntSetRanges ev_r(ev); IntSetRanges dom_r(dom); oob = !Ranges::subset(ev_r, dom_r); } else { oob = !dom->contains(eval_int(env,e)); } } if (oob) { std::ostringstream oss; oss << "value for argument `" << *arg << "' out of bounds"; throw EvalError(env, e->loc(), oss.str()); } } void checkDom(EnvI& env, Id* arg, FloatVal dom_min, FloatVal dom_max, Expression* e) { if (!e->type().isopt()) { FloatVal ev = eval_float(env, e); if (ev < dom_min || ev > dom_max) { std::ostringstream oss; oss << "value for argument `" << *arg << "' out of bounds"; throw EvalError(env, e->loc(), oss.str()); } } } template typename Eval::Val eval_call(EnvI& env, CallClass* ce) { std::vector previousParameters(ce->decl()->params().size()); std::vector params(ce->decl()->params().size()); for (unsigned int i=0; idecl()->params().size(); i++) { params[i] = eval_par(env, ce->arg(i)); } for (unsigned int i=ce->decl()->params().size(); i--;) { VarDecl* vd = ce->decl()->params()[i]; if (vd->type().dim() > 0) { // Check array index sets ArrayLit* al = params[i]->cast(); for (unsigned int j=0; jti()->ranges().size(); j++) { TypeInst* range_ti = vd->ti()->ranges()[j]; if (range_ti->domain() && !range_ti->domain()->isa()) { IntSetVal* isv = eval_intset(env, range_ti->domain()); if (isv->min() != al->min(j) || isv->max() != al->max(j)) { std::ostringstream oss; oss << "array index set " << (j+1) << " of argument " << (i+1) << " does not match declared index set"; throw EvalError(env, ce->loc(), oss.str()); } } } } previousParameters[i] = vd->e(); vd->flat(vd); vd->e(params[i]); if (vd->e()->type().ispar()) { if (Expression* dom = vd->ti()->domain()) { if (!dom->isa()) { if (vd->e()->type().bt()==Type::BT_INT) { IntSetVal* isv = eval_intset(env, dom); if (vd->e()->type().dim() > 0) { ArrayLit* al = eval_array_lit(env, vd->e()); for (unsigned int i=0; isize(); i++) { checkDom(env, vd->id(), isv, (*al)[i]); } } else { checkDom(env, vd->id(),isv, vd->e()); } } else if (vd->e()->type().bt()==Type::BT_FLOAT) { GCLock lock; FloatSetVal* fsv = eval_floatset(env, dom); FloatVal dom_min = fsv->min(); FloatVal dom_max = fsv->max(); checkDom(env, vd->id(), dom_min, dom_max, vd->e()); } } } } } typename Eval::Val ret = Eval::e(env,ce->decl()->e()); Eval::checkRetVal(env, ret, ce->decl()); for (unsigned int i=ce->decl()->params().size(); i--;) { VarDecl* vd = ce->decl()->params()[i]; vd->e(previousParameters[i]); vd->flat(vd->e() ? vd : NULL); } return ret; } ArrayLit* eval_array_comp(EnvI& env, Comprehension* e) { ArrayLit* ret; if (e->type() == Type::parint(1)) { std::vector a = eval_comp(env,e); ret = new ArrayLit(e->loc(),a); } else if (e->type() == Type::parbool(1)) { std::vector a = eval_comp(env,e); ret = new ArrayLit(e->loc(),a); } else if (e->type() == Type::parfloat(1)) { std::vector a = eval_comp(env,e); ret = new ArrayLit(e->loc(),a); } else if (e->type().st()==Type::ST_SET) { std::vector a = eval_comp(env,e); ret = new ArrayLit(e->loc(),a); } else if (e->type() == Type::parstring(1)) { std::vector a = eval_comp(env,e); ret = new ArrayLit(e->loc(),a); } else { std::vector a = eval_comp(env,e); ret = new ArrayLit(e->loc(),a); } ret->type(e->type()); return ret; } ArrayLit* eval_array_lit(EnvI& env, Expression* e) { CallStackItem csi(env,e); switch (e->eid()) { case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_BOOLLIT: case Expression::E_STRINGLIT: case Expression::E_SETLIT: case Expression::E_ANON: case Expression::E_TI: case Expression::E_TIID: case Expression::E_VARDECL: throw EvalError(env, e->loc(), "not an array expression"); case Expression::E_ID: return eval_id(env,e); case Expression::E_ARRAYLIT: return e->cast(); case Expression::E_ARRAYACCESS: throw EvalError(env, e->loc(),"arrays of arrays not supported"); case Expression::E_COMP: return eval_array_comp(env,e->cast()); case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { if (eval_bool(env,ite->e_if(i))) return eval_array_lit(env,ite->e_then(i)); } return eval_array_lit(env,ite->e_else()); } case Expression::E_BINOP: { BinOp* bo = e->cast(); if (bo->op()==BOT_PLUSPLUS) { ArrayLit* al0 = eval_array_lit(env,bo->lhs()); ArrayLit* al1 = eval_array_lit(env,bo->rhs()); std::vector v(al0->size()+al1->size()); for (unsigned int i=al0->size(); i--;) v[i] = (*al0)[i]; for (unsigned int i=al1->size(); i--;) v[al0->size()+i] = (*al1)[i]; ArrayLit* ret = new ArrayLit(e->loc(),v); ret->flat(al0->flat() && al1->flat()); ret->type(e->type()); return ret; } else { if (bo->decl() && bo->decl()->e()) { return eval_call(env,bo); } throw EvalError(env, e->loc(), "not an array expression", bo->opToString()); } } break; case Expression::E_UNOP: { UnOp* uo = e->cast(); if (uo->decl() && uo->decl()->e()) { return eval_call(env,uo); } throw EvalError(env, e->loc(), "not an array expression"); } case Expression::E_CALL: { Call* ce = e->cast(); if (ce->decl()==NULL) throw EvalError(env, e->loc(), "undeclared function", ce->id()); if (ce->decl()->_builtins.e) return eval_array_lit(env,ce->decl()->_builtins.e(env,ce)); if (ce->decl()->e()==NULL) throw EvalError(env, ce->loc(), "internal error: missing builtin '"+ce->id().str()+"'"); return eval_call(env,ce); } case Expression::E_LET: { Let* l = e->cast(); l->pushbindings(); for (unsigned int i=0; ilet().size(); i++) { // Evaluate all variable declarations if (VarDecl* vdi = l->let()[i]->dyn_cast()) { vdi->e(eval_par(env, vdi->e())); if (vdi->ti()->domain()) { if (!checkParDomain(env, vdi->e(), vdi->ti()->domain())) { throw ResultUndefinedError(env, l->let()[i]->loc(),"domain constraint in let failed"); } } } else { // This is a constraint item. Since the let is par, // it can only be a par bool expression. If it evaluates // to false, it means that the value of this let is undefined. if (!eval_bool(env, l->let()[i])) { throw ResultUndefinedError(env, l->let()[i]->loc(),"constraint in let failed"); } } } ArrayLit* l_in = eval_array_lit(env,l->in()); ArrayLit* ret = copy(env,l_in,true)->cast(); ret->flat(l_in->flat()); l->popbindings(); return ret; } } assert(false); return NULL; } Expression* eval_arrayaccess(EnvI& env, ArrayLit* al, const std::vector& dims, bool& success) { success = true; assert(al->dims() == dims.size()); IntVal realidx = 0; int realdim = 1; for (int i=0; idims(); i++) realdim *= al->max(i)-al->min(i)+1; for (int i=0; idims(); i++) { IntVal ix = dims[i]; if (ix < al->min(i) || ix > al->max(i)) { success = false; Type t = al->type(); t.dim(0); if (t.isint()) return IntLit::a(0); if (t.isbool()) return constants().lit_false; if (t.isfloat()) return FloatLit::a(0.0); if (t.st() == Type::ST_SET || t.isbot()) { SetLit* ret = new SetLit(Location(),std::vector()); ret->type(t); return ret; } if (t.isstring()) return new StringLit(Location(),""); throw EvalError(env, al->loc(), "Internal error: unexpected type in array access expression"); } realdim /= al->max(i)-al->min(i)+1; realidx += (ix-al->min(i))*realdim; } assert(realidx >= 0 && realidx <= al->size()); return (*al)[static_cast(realidx.toInt())]; } Expression* eval_arrayaccess(EnvI& env, ArrayAccess* e, bool& success) { ArrayLit* al = eval_array_lit(env,e->v()); std::vector dims(e->idx().size()); for (unsigned int i=e->idx().size(); i--;) { dims[i] = eval_int(env,e->idx()[i]); } return eval_arrayaccess(env,al,dims,success); } Expression* eval_arrayaccess(EnvI& env, ArrayAccess* e) { bool success; Expression* ret = eval_arrayaccess(env,e,success); if (success) return ret; else throw ResultUndefinedError(env, e->loc(), "array access out of bounds"); } IntSetVal* eval_intset(EnvI& env, Expression* e) { if (SetLit* sl = e->dyn_cast()) { if (sl->isv()) return sl->isv(); } CallStackItem csi(env,e); switch (e->eid()) { case Expression::E_SETLIT: { SetLit* sl = e->cast(); std::vector vals(sl->v().size()); for (unsigned int i=0; iv().size(); i++) vals[i] = eval_int(env,sl->v()[i]); return IntSetVal::a(vals); } case Expression::E_BOOLLIT: case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_STRINGLIT: case Expression::E_ANON: case Expression::E_TIID: case Expression::E_VARDECL: case Expression::E_TI: throw EvalError(env, e->loc(),"not a set of int expression"); break; case Expression::E_ARRAYLIT: { ArrayLit* al = e->cast(); std::vector vals(al->size()); for (unsigned int i=0; isize(); i++) vals[i] = eval_int(env,(*al)[i]); return IntSetVal::a(vals); } break; case Expression::E_COMP: { Comprehension* c = e->cast(); std::vector a = eval_comp(env,c); return IntSetVal::a(a); } case Expression::E_ID: { GCLock lock; return eval_id(env,e)->isv(); } break; case Expression::E_ARRAYACCESS: { GCLock lock; return eval_intset(env,eval_arrayaccess(env,e->cast())); } break; case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { if (eval_bool(env,ite->e_if(i))) return eval_intset(env,ite->e_then(i)); } return eval_intset(env,ite->e_else()); } break; case Expression::E_BINOP: { BinOp* bo = e->cast(); if (bo->decl() && bo->decl()->e()) { return eval_call(env,bo); } Expression* lhs = eval_par(env, bo->lhs()); Expression* rhs = eval_par(env, bo->rhs()); if (lhs->type().isintset() && rhs->type().isintset()) { IntSetVal* v0 = eval_intset(env,lhs); IntSetVal* v1 = eval_intset(env,rhs); IntSetRanges ir0(v0); IntSetRanges ir1(v1); switch (bo->op()) { case BOT_UNION: { Ranges::Union u(ir0,ir1); return IntSetVal::ai(u); } case BOT_DIFF: { Ranges::Diff u(ir0,ir1); return IntSetVal::ai(u); } case BOT_SYMDIFF: { Ranges::Union u(ir0,ir1); Ranges::Inter i(ir0,ir1); Ranges::Diff, Ranges::Inter> sd(u,i); return IntSetVal::ai(sd); } case BOT_INTERSECT: { Ranges::Inter u(ir0,ir1); return IntSetVal::ai(u); } default: throw EvalError(env, e->loc(),"not a set of int expression", bo->opToString()); } } else if (lhs->type().isint() && rhs->type().isint()) { if (bo->op() != BOT_DOTDOT) throw EvalError(env, e->loc(), "not a set of int expression", bo->opToString()); return IntSetVal::a(eval_int(env,lhs), eval_int(env,rhs)); } else { throw EvalError(env, e->loc(), "not a set of int expression", bo->opToString()); } } break; case Expression::E_UNOP: { UnOp* uo = e->cast(); if (uo->decl() && uo->decl()->e()) { return eval_call(env,uo); } throw EvalError(env, e->loc(),"not a set of int expression"); } case Expression::E_CALL: { Call* ce = e->cast(); if (ce->decl()==NULL) throw EvalError(env, e->loc(), "undeclared function", ce->id()); if (ce->decl()->_builtins.s) return ce->decl()->_builtins.s(env,ce); if (ce->decl()->_builtins.e) return eval_intset(env,ce->decl()->_builtins.e(env,ce)); if (ce->decl()->e()==NULL) throw EvalError(env, ce->loc(), "internal error: missing builtin '"+ce->id().str()+"'"); return eval_call(env,ce); } break; case Expression::E_LET: { Let* l = e->cast(); l->pushbindings(); for (unsigned int i=0; ilet().size(); i++) { // Evaluate all variable declarations if (VarDecl* vdi = l->let()[i]->dyn_cast()) { vdi->e(eval_par(env, vdi->e())); if (vdi->ti()->domain()) { if (!checkParDomain(env, vdi->e(), vdi->ti()->domain())) { throw ResultUndefinedError(env, l->let()[i]->loc(),"domain constraint in let failed"); } } } else { // This is a constraint item. Since the let is par, // it can only be a par bool expression. If it evaluates // to false, it means that the value of this let is undefined. if (!eval_bool(env, l->let()[i])) { throw ResultUndefinedError(env, l->let()[i]->loc(),"constraint in let failed"); } } } IntSetVal* ret = eval_intset(env,l->in()); l->popbindings(); return ret; } break; default: assert(false); return NULL; } } FloatSetVal* eval_floatset(EnvI& env, Expression* e) { if (SetLit* sl = e->dyn_cast()) { if (sl->fsv()) return sl->fsv(); } CallStackItem csi(env,e); switch (e->eid()) { case Expression::E_SETLIT: { SetLit* sl = e->cast(); std::vector vals(sl->v().size()); for (unsigned int i=0; iv().size(); i++) vals[i] = eval_float(env,sl->v()[i]); return FloatSetVal::a(vals); } case Expression::E_BOOLLIT: case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_STRINGLIT: case Expression::E_ANON: case Expression::E_TIID: case Expression::E_VARDECL: case Expression::E_TI: throw EvalError(env, e->loc(),"not a set of float expression"); break; case Expression::E_ARRAYLIT: { ArrayLit* al = e->cast(); std::vector vals(al->size()); for (unsigned int i=0; isize(); i++) vals[i] = eval_float(env,(*al)[i]); return FloatSetVal::a(vals); } break; case Expression::E_COMP: { Comprehension* c = e->cast(); std::vector a = eval_comp(env,c); return FloatSetVal::a(a); } case Expression::E_ID: { GCLock lock; return eval_floatset(env, eval_id(env,e)); } break; case Expression::E_ARRAYACCESS: { GCLock lock; return eval_floatset(env,eval_arrayaccess(env,e->cast())); } break; case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { if (eval_bool(env,ite->e_if(i))) return eval_floatset(env,ite->e_then(i)); } return eval_floatset(env,ite->e_else()); } break; case Expression::E_BINOP: { BinOp* bo = e->cast(); if (bo->decl() && bo->decl()->e()) { return eval_call(env,bo); } Expression* lhs = eval_par(env, bo->lhs()); Expression* rhs = eval_par(env, bo->rhs()); if (lhs->type().isfloatset() && rhs->type().isfloatset()) { FloatSetVal* v0 = eval_floatset(env,lhs); FloatSetVal* v1 = eval_floatset(env,rhs); FloatSetRanges fr0(v0); FloatSetRanges fr1(v1); switch (bo->op()) { case BOT_UNION: { Ranges::Union u(fr0,fr1); return FloatSetVal::ai(u); } case BOT_DIFF: { Ranges::Diff u(fr0,fr1); return FloatSetVal::ai(u); } case BOT_SYMDIFF: { Ranges::Union u(fr0,fr1); Ranges::Inter i(fr0,fr1); Ranges::Diff, Ranges::Inter> sd(u,i); return FloatSetVal::ai(sd); } case BOT_INTERSECT: { Ranges::Inter u(fr0,fr1); return FloatSetVal::ai(u); } default: throw EvalError(env, e->loc(),"not a set of int expression", bo->opToString()); } } else if (lhs->type().isfloat() && rhs->type().isfloat()) { if (bo->op() != BOT_DOTDOT) throw EvalError(env, e->loc(), "not a set of float expression", bo->opToString()); return FloatSetVal::a(eval_float(env, lhs), eval_float(env, rhs)); } else { throw EvalError(env, e->loc(), "not a set of float expression", bo->opToString()); } } break; case Expression::E_UNOP: { UnOp* uo = e->cast(); if (uo->decl() && uo->decl()->e()) { return eval_call(env,uo); } throw EvalError(env, e->loc(),"not a set of float expression"); } case Expression::E_CALL: { Call* ce = e->cast(); if (ce->decl()==NULL) throw EvalError(env, e->loc(), "undeclared function", ce->id()); if (ce->decl()->_builtins.e) return eval_floatset(env,ce->decl()->_builtins.e(env,ce)); if (ce->decl()->e()==NULL) throw EvalError(env, ce->loc(), "internal error: missing builtin '"+ce->id().str()+"'"); return eval_call(env,ce); } break; case Expression::E_LET: { Let* l = e->cast(); l->pushbindings(); for (unsigned int i=0; ilet().size(); i++) { // Evaluate all variable declarations if (VarDecl* vdi = l->let()[i]->dyn_cast()) { vdi->e(eval_par(env, vdi->e())); if (vdi->ti()->domain()) { if (!checkParDomain(env, vdi->e(), vdi->ti()->domain())) { throw ResultUndefinedError(env, l->let()[i]->loc(),"domain constraint in let failed"); } } } else { // This is a constraint item. Since the let is par, // it can only be a par bool expression. If it evaluates // to false, it means that the value of this let is undefined. if (!eval_bool(env, l->let()[i])) { throw ResultUndefinedError(env, l->let()[i]->loc(),"constraint in let failed"); } } } FloatSetVal* ret = eval_floatset(env,l->in()); l->popbindings(); return ret; } break; default: assert(false); return NULL; } } bool eval_bool(EnvI& env, Expression* e) { CallStackItem csi(env,e); try { if (BoolLit* bl = e->dyn_cast()) { return bl->v(); } CallStackItem csi(env,e); switch (e->eid()) { case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_STRINGLIT: case Expression::E_ANON: case Expression::E_TIID: case Expression::E_SETLIT: case Expression::E_ARRAYLIT: case Expression::E_COMP: case Expression::E_VARDECL: case Expression::E_TI: assert(false); throw EvalError(env, e->loc(),"not a bool expression"); break; case Expression::E_ID: { GCLock lock; return eval_id(env,e)->v(); } break; case Expression::E_ARRAYACCESS: { GCLock lock; return eval_bool(env,eval_arrayaccess(env,e->cast())); } break; case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { if (eval_bool(env,ite->e_if(i))) return eval_bool(env,ite->e_then(i)); } return eval_bool(env,ite->e_else()); } break; case Expression::E_BINOP: { BinOp* bo = e->cast(); Expression* lhs = bo->lhs(); if (lhs->type().bt()==Type::BT_TOP) lhs = eval_par(env,lhs); Expression* rhs = bo->rhs(); if (rhs->type().bt()==Type::BT_TOP) rhs = eval_par(env,rhs); if ( bo->op()==BOT_EQ && (lhs->type().isopt() || rhs->type().isopt()) ) { if (lhs == constants().absent || rhs==constants().absent) return lhs==rhs; } if (bo->decl() && bo->decl()->e()) { return eval_call(env,bo); } if (lhs->type().isbool() && rhs->type().isbool()) { try { switch (bo->op()) { case BOT_LE: return eval_bool(env,lhs)eval_bool(env,rhs); case BOT_GQ: return eval_bool(env,lhs)>=eval_bool(env,rhs); case BOT_EQ: return eval_bool(env,lhs)==eval_bool(env,rhs); case BOT_NQ: return eval_bool(env,lhs)!=eval_bool(env,rhs); case BOT_EQUIV: return eval_bool(env,lhs)==eval_bool(env,rhs); case BOT_IMPL: return (!eval_bool(env,lhs))||eval_bool(env,rhs); case BOT_RIMPL: return (!eval_bool(env,rhs))||eval_bool(env,lhs); case BOT_OR: return eval_bool(env,lhs)||eval_bool(env,rhs); case BOT_AND: return eval_bool(env,lhs)&&eval_bool(env,rhs); case BOT_XOR: return eval_bool(env,lhs)^eval_bool(env,rhs); default: assert(false); throw EvalError(env, e->loc(),"not a bool expression", bo->opToString()); } } catch (ResultUndefinedError&) { return false; } } else if (lhs->type().isint() && rhs->type().isint()) { try { IntVal v0 = eval_int(env,lhs); IntVal v1 = eval_int(env,rhs); switch (bo->op()) { case BOT_LE: return v0v1; case BOT_GQ: return v0>=v1; case BOT_EQ: return v0==v1; case BOT_NQ: return v0!=v1; default: assert(false); throw EvalError(env, e->loc(),"not a bool expression", bo->opToString()); } } catch (ResultUndefinedError&) { return false; } } else if (lhs->type().isfloat() && rhs->type().isfloat()) { try { FloatVal v0 = eval_float(env,lhs); FloatVal v1 = eval_float(env,rhs); switch (bo->op()) { case BOT_LE: return v0v1; case BOT_GQ: return v0>=v1; case BOT_EQ: return v0==v1; case BOT_NQ: return v0!=v1; default: assert(false); throw EvalError(env, e->loc(),"not a bool expression", bo->opToString()); } } catch (ResultUndefinedError&) { return false; } } else if (lhs->type().isint() && rhs->type().isintset()) { try { IntVal v0 = eval_int(env,lhs); GCLock lock; IntSetVal* v1 = eval_intset(env,rhs); switch (bo->op()) { case BOT_IN: return v1->contains(v0); default: assert(false); throw EvalError(env, e->loc(),"not a bool expression", bo->opToString()); } } catch (ResultUndefinedError&) { return false; } } else if (lhs->type().isfloat() && rhs->type().isfloatset()) { try { FloatVal v0 = eval_float(env,lhs); GCLock lock; FloatSetVal* v1 = eval_floatset(env,rhs); switch (bo->op()) { case BOT_IN: return v1->contains(v0); default: assert(false); throw EvalError(env, e->loc(),"not a bool expression", bo->opToString()); } } catch (ResultUndefinedError&) { return false; } } else if (lhs->type().is_set() && rhs->type().is_set()) { try { GCLock lock; IntSetVal* v0 = eval_intset(env,lhs); IntSetVal* v1 = eval_intset(env,rhs); IntSetRanges ir0(v0); IntSetRanges ir1(v1); switch (bo->op()) { case BOT_LE: return Ranges::less(ir0,ir1); case BOT_LQ: return Ranges::lessEq(ir0,ir1); case BOT_GR: return Ranges::less(ir1,ir0); case BOT_GQ: return Ranges::lessEq(ir1,ir0); case BOT_EQ: return Ranges::equal(ir0,ir1); case BOT_NQ: return !Ranges::equal(ir0,ir1); case BOT_SUBSET: return Ranges::subset(ir0,ir1); case BOT_SUPERSET: return Ranges::subset(ir1,ir0); default: throw EvalError(env, e->loc(),"not a bool expression", bo->opToString()); } } catch (ResultUndefinedError&) { return false; } } else if (lhs->type().isstring() && rhs->type().isstring()) { try { GCLock lock; std::string s0 = eval_string(env,lhs); std::string s1 = eval_string(env,rhs); switch (bo->op()) { case BOT_EQ: return s0==s1; case BOT_NQ: return s0!=s1; case BOT_LE: return s0s1; case BOT_GQ: return s0>=s1; default: throw EvalError(env, e->loc(),"not a bool expression", bo->opToString()); } } catch (ResultUndefinedError&) { return false; } } else if (bo->op()==BOT_EQ && lhs->type().isann()) { return Expression::equal(lhs, rhs); } else if (bo->op()==BOT_EQ && lhs->type().dim() > 0 && rhs->type().dim() > 0) { try { ArrayLit* al0 = eval_array_lit(env,lhs); ArrayLit* al1 = eval_array_lit(env,rhs); if (al0->size() != al1->size()) return false; for (unsigned int i=0; isize(); i++) { if (!Expression::equal(eval_par(env,(*al0)[i]), eval_par(env,(*al1)[i]))) { return false; } } return true; } catch (ResultUndefinedError&) { return false; } } else { throw EvalError(env, e->loc(), "not a bool expression", bo->opToString()); } } break; case Expression::E_UNOP: { UnOp* uo = e->cast(); if (uo->decl() && uo->decl()->e()) { return eval_call(env,uo); } bool v0 = eval_bool(env,uo->e()); switch (uo->op()) { case UOT_NOT: return !v0; default: assert(false); throw EvalError(env, e->loc(),"not a bool expression", uo->opToString()); } } break; case Expression::E_CALL: { try { Call* ce = e->cast(); if (ce->decl()==NULL) throw EvalError(env, e->loc(), "undeclared function", ce->id()); if (ce->decl()->_builtins.b) return ce->decl()->_builtins.b(env,ce); if (ce->decl()->_builtins.e) return eval_bool(env,ce->decl()->_builtins.e(env,ce)); if (ce->decl()->e()==NULL) throw EvalError(env, ce->loc(), "internal error: missing builtin '"+ce->id().str()+"'"); return eval_call(env,ce); } catch (ResultUndefinedError&) { return false; } } break; case Expression::E_LET: { Let* l = e->cast(); l->pushbindings(); bool ret = true; for (unsigned int i=0; ilet().size(); i++) { // Evaluate all variable declarations if (VarDecl* vdi = l->let()[i]->dyn_cast()) { vdi->e(eval_par(env, vdi->e())); if (vdi->ti()->domain()) { if (!checkParDomain(env, vdi->e(), vdi->ti()->domain())) { if (vdi->ann().contains(constants().ann.maybe_partial)) { ret = false; } else { throw ResultUndefinedError(env, l->let()[i]->loc(),"domain constraint in let failed"); } } } } else { // This is a constraint item. Since the let is par, // it can only be a par bool expression. If it evaluates // to false, it means that the value of this let is false. if (!eval_bool(env, l->let()[i])) { if (l->let()[i]->ann().contains(constants().ann.maybe_partial)) { ret = false; } else { throw ResultUndefinedError(env, l->let()[i]->loc(),"domain constraint in let failed"); } } } } ret = ret && eval_bool(env,l->in()); l->popbindings(); return ret; } break; default: assert(false); return false; } } catch (ResultUndefinedError&) { // undefined means false return false; } } IntSetVal* eval_boolset(EnvI& env, Expression* e) { CallStackItem csi(env,e); switch (e->eid()) { case Expression::E_SETLIT: { SetLit* sl = e->cast(); if (sl->isv()) return sl->isv(); std::vector vals(sl->v().size()); for (unsigned int i=0; iv().size(); i++) vals[i] = eval_bool(env,sl->v()[i]); return IntSetVal::a(vals); } case Expression::E_BOOLLIT: case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_STRINGLIT: case Expression::E_ANON: case Expression::E_TIID: case Expression::E_VARDECL: case Expression::E_TI: throw EvalError(env, e->loc(),"not a set of bool expression"); break; case Expression::E_ARRAYLIT: { ArrayLit* al = e->cast(); std::vector vals(al->size()); for (unsigned int i=0; isize(); i++) vals[i] = eval_bool(env,(*al)[i]); return IntSetVal::a(vals); } break; case Expression::E_COMP: { Comprehension* c = e->cast(); std::vector a = eval_comp(env,c); return IntSetVal::a(a); } case Expression::E_ID: { GCLock lock; return eval_id(env,e)->isv(); } break; case Expression::E_ARRAYACCESS: { GCLock lock; return eval_boolset(env,eval_arrayaccess(env,e->cast())); } break; case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { if (eval_bool(env,ite->e_if(i))) return eval_boolset(env,ite->e_then(i)); } return eval_boolset(env,ite->e_else()); } break; case Expression::E_BINOP: { BinOp* bo = e->cast(); if (bo->decl() && bo->decl()->e()) { return eval_call(env,bo); } Expression* lhs = eval_par(env, bo->lhs()); Expression* rhs = eval_par(env, bo->rhs()); if (lhs->type().isintset() && rhs->type().isintset()) { IntSetVal* v0 = eval_boolset(env,lhs); IntSetVal* v1 = eval_boolset(env,rhs); IntSetRanges ir0(v0); IntSetRanges ir1(v1); switch (bo->op()) { case BOT_UNION: { Ranges::Union u(ir0,ir1); return IntSetVal::ai(u); } case BOT_DIFF: { Ranges::Diff u(ir0,ir1); return IntSetVal::ai(u); } case BOT_SYMDIFF: { Ranges::Union u(ir0,ir1); Ranges::Inter i(ir0,ir1); Ranges::Diff, Ranges::Inter> sd(u,i); return IntSetVal::ai(sd); } case BOT_INTERSECT: { Ranges::Inter u(ir0,ir1); return IntSetVal::ai(u); } default: throw EvalError(env, e->loc(),"not a set of bool expression", bo->opToString()); } } else if (lhs->type().isbool() && rhs->type().isbool()) { if (bo->op() != BOT_DOTDOT) throw EvalError(env, e->loc(), "not a set of bool expression", bo->opToString()); return IntSetVal::a(eval_bool(env,lhs), eval_bool(env,rhs)); } else { throw EvalError(env, e->loc(), "not a set of bool expression", bo->opToString()); } } break; case Expression::E_UNOP: { UnOp* uo = e->cast(); if (uo->decl() && uo->decl()->e()) { return eval_call(env,uo); } throw EvalError(env, e->loc(),"not a set of bool expression"); } case Expression::E_CALL: { Call* ce = e->cast(); if (ce->decl()==NULL) throw EvalError(env, e->loc(), "undeclared function", ce->id()); if (ce->decl()->_builtins.s) return ce->decl()->_builtins.s(env,ce); if (ce->decl()->_builtins.e) return eval_boolset(env,ce->decl()->_builtins.e(env,ce)); if (ce->decl()->e()==NULL) throw EvalError(env, ce->loc(), "internal error: missing builtin '"+ce->id().str()+"'"); return eval_call(env,ce); } break; case Expression::E_LET: { Let* l = e->cast(); l->pushbindings(); for (unsigned int i=0; ilet().size(); i++) { // Evaluate all variable declarations if (VarDecl* vdi = l->let()[i]->dyn_cast()) { vdi->e(eval_par(env, vdi->e())); if (vdi->ti()->domain()) { if (!checkParDomain(env, vdi->e(), vdi->ti()->domain())) { throw ResultUndefinedError(env, l->let()[i]->loc(),"domain constraint in let failed"); } } } else { // This is a constraint item. Since the let is par, // it can only be a par bool expression. If it evaluates // to false, it means that the value of this let is undefined. if (!eval_bool(env, l->let()[i])) { throw ResultUndefinedError(env, l->let()[i]->loc(),"constraint in let failed"); } } } IntSetVal* ret = eval_boolset(env,l->in()); l->popbindings(); return ret; } break; default: assert(false); return NULL; } } IntVal eval_int(EnvI& env,Expression* e) { if (e->type().isbool()) { return eval_bool(env,e); } if (IntLit* il = e->dyn_cast()) { return il->v(); } CallStackItem csi(env,e); try { switch (e->eid()) { case Expression::E_FLOATLIT: case Expression::E_BOOLLIT: case Expression::E_STRINGLIT: case Expression::E_ANON: case Expression::E_TIID: case Expression::E_SETLIT: case Expression::E_ARRAYLIT: case Expression::E_COMP: case Expression::E_VARDECL: case Expression::E_TI: throw EvalError(env, e->loc(),"not an integer expression"); break; case Expression::E_ID: { GCLock lock; return eval_id(env,e)->v(); } break; case Expression::E_ARRAYACCESS: { GCLock lock; return eval_int(env,eval_arrayaccess(env,e->cast())); } break; case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { if (eval_bool(env,ite->e_if(i))) return eval_int(env,ite->e_then(i)); } return eval_int(env,ite->e_else()); } break; case Expression::E_BINOP: { BinOp* bo = e->cast(); if (bo->decl() && bo->decl()->e()) { return eval_call(env,bo); } IntVal v0 = eval_int(env,bo->lhs()); IntVal v1 = eval_int(env,bo->rhs()); switch (bo->op()) { case BOT_PLUS: return v0+v1; case BOT_MINUS: return v0-v1; case BOT_MULT: return v0*v1; case BOT_POW: return v0.pow(v1); case BOT_IDIV: if (v1==0) throw ResultUndefinedError(env, e->loc(),"division by zero"); return v0 / v1; case BOT_MOD: if (v1==0) throw ResultUndefinedError(env, e->loc(),"division by zero"); return v0 % v1; default: throw EvalError(env, e->loc(),"not an integer expression", bo->opToString()); } } break; case Expression::E_UNOP: { UnOp* uo = e->cast(); if (uo->decl() && uo->decl()->e()) { return eval_call(env,uo); } IntVal v0 = eval_int(env,uo->e()); switch (uo->op()) { case UOT_PLUS: return v0; case UOT_MINUS: return -v0; default: throw EvalError(env, e->loc(),"not an integer expression", uo->opToString()); } } break; case Expression::E_CALL: { Call* ce = e->cast(); if (ce->decl()==NULL) throw EvalError(env, e->loc(), "undeclared function", ce->id()); if (ce->decl()->_builtins.i) return ce->decl()->_builtins.i(env,ce); if (ce->decl()->_builtins.e) return eval_int(env,ce->decl()->_builtins.e(env,ce)); if (ce->decl()->e()==NULL) throw EvalError(env, ce->loc(), "internal error: missing builtin '"+ce->id().str()+"'"); return eval_call(env,ce); } break; case Expression::E_LET: { Let* l = e->cast(); l->pushbindings(); for (unsigned int i=0; ilet().size(); i++) { // Evaluate all variable declarations if (VarDecl* vdi = l->let()[i]->dyn_cast()) { vdi->e(eval_par(env, vdi->e())); if (vdi->ti()->domain()) { if (!checkParDomain(env, vdi->e(), vdi->ti()->domain())) { throw ResultUndefinedError(env, l->let()[i]->loc(),"domain constraint in let failed"); } } } else { // This is a constraint item. Since the let is par, // it can only be a par bool expression. If it evaluates // to false, it means that the value of this let is undefined. if (!eval_bool(env, l->let()[i])) { throw ResultUndefinedError(env, l->let()[i]->loc(),"constraint in let failed"); } } } IntVal ret = eval_int(env,l->in()); l->popbindings(); return ret; } break; default: assert(false); return 0; } } catch (ArithmeticError& err) { throw EvalError(env, e->loc(), err.msg()); } } FloatVal eval_float(EnvI& env, Expression* e) { CallStackItem csi(env,e); try { if (e->type().isint()) { return FloatVal(eval_int(env,e).toInt()); } else if (e->type().isbool()) { return eval_bool(env,e); } if (FloatLit* fl = e->dyn_cast()) { return fl->v(); } CallStackItem csi(env,e); switch (e->eid()) { case Expression::E_INTLIT: case Expression::E_BOOLLIT: case Expression::E_STRINGLIT: case Expression::E_ANON: case Expression::E_TIID: case Expression::E_SETLIT: case Expression::E_ARRAYLIT: case Expression::E_COMP: case Expression::E_VARDECL: case Expression::E_TI: throw EvalError(env, e->loc(),"not a float expression"); break; case Expression::E_ID: { GCLock lock; return eval_id(env,e)->v(); } break; case Expression::E_ARRAYACCESS: { GCLock lock; return eval_float(env,eval_arrayaccess(env,e->cast())); } break; case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { if (eval_bool(env,ite->e_if(i))) return eval_float(env,ite->e_then(i)); } return eval_float(env,ite->e_else()); } break; case Expression::E_BINOP: { BinOp* bo = e->cast(); if (bo->decl() && bo->decl()->e()) { return eval_call(env,bo); } FloatVal v0 = eval_float(env,bo->lhs()); FloatVal v1 = eval_float(env,bo->rhs()); switch (bo->op()) { case BOT_PLUS: return v0+v1; case BOT_MINUS: return v0-v1; case BOT_MULT: return v0*v1; case BOT_POW: return std::pow(v0.toDouble(),v1.toDouble()); case BOT_DIV: if (v1==0.0) throw ResultUndefinedError(env, e->loc(),"division by zero"); return v0 / v1; default: throw EvalError(env, e->loc(),"not a float expression", bo->opToString()); } } break; case Expression::E_UNOP: { UnOp* uo = e->cast(); if (uo->decl() && uo->decl()->e()) { return eval_call(env,uo); } FloatVal v0 = eval_float(env,uo->e()); switch (uo->op()) { case UOT_PLUS: return v0; case UOT_MINUS: return -v0; default: throw EvalError(env, e->loc(),"not a float expression", uo->opToString()); } } break; case Expression::E_CALL: { Call* ce = e->cast(); if (ce->decl()==NULL) throw EvalError(env, e->loc(), "undeclared function", ce->id()); if (ce->decl()->_builtins.f) return ce->decl()->_builtins.f(env,ce); if (ce->decl()->_builtins.e) return eval_float(env,ce->decl()->_builtins.e(env,ce)); if (ce->decl()->e()==NULL) throw EvalError(env, ce->loc(), "internal error: missing builtin '"+ce->id().str()+"'"); return eval_call(env,ce); } break; case Expression::E_LET: { Let* l = e->cast(); l->pushbindings(); for (unsigned int i=0; ilet().size(); i++) { // Evaluate all variable declarations if (VarDecl* vdi = l->let()[i]->dyn_cast()) { vdi->e(eval_par(env, vdi->e())); if (vdi->ti()->domain()) { if (!checkParDomain(env, vdi->e(), vdi->ti()->domain())) { throw ResultUndefinedError(env, l->let()[i]->loc(),"domain constraint in let failed"); } } } else { // This is a constraint item. Since the let is par, // it can only be a par bool expression. If it evaluates // to false, it means that the value of this let is undefined. if (!eval_bool(env, l->let()[i])) { throw ResultUndefinedError(env, l->let()[i]->loc(),"constraint in let failed"); } } } FloatVal ret = eval_float(env,l->in()); l->popbindings(); return ret; } break; default: assert(false); return 0.0; } } catch(ArithmeticError& err) { throw EvalError(env, e->loc(), err.msg()); } } std::string eval_string(EnvI& env, Expression* e) { CallStackItem csi(env,e); switch (e->eid()) { case Expression::E_STRINGLIT: return e->cast()->v().str(); case Expression::E_FLOATLIT: case Expression::E_INTLIT: case Expression::E_BOOLLIT: case Expression::E_ANON: case Expression::E_TIID: case Expression::E_SETLIT: case Expression::E_ARRAYLIT: case Expression::E_COMP: case Expression::E_VARDECL: case Expression::E_TI: throw EvalError(env, e->loc(),"not a string expression"); break; case Expression::E_ID: { GCLock lock; return eval_id(env,e)->v().str(); } break; case Expression::E_ARRAYACCESS: { GCLock lock; return eval_string(env,eval_arrayaccess(env,e->cast())); } break; case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { if (eval_bool(env,ite->e_if(i))) return eval_string(env,ite->e_then(i)); } return eval_string(env,ite->e_else()); } break; case Expression::E_BINOP: { BinOp* bo = e->cast(); if (bo->decl() && bo->decl()->e()) { return eval_call(env,bo); } std::string v0 = eval_string(env,bo->lhs()); std::string v1 = eval_string(env,bo->rhs()); switch (bo->op()) { case BOT_PLUSPLUS: return v0+v1; default: throw EvalError(env, e->loc(),"not a string expression", bo->opToString()); } } break; case Expression::E_UNOP: { UnOp* uo = e->cast(); if (uo->decl() && uo->decl()->e()) { return eval_call(env,uo); } throw EvalError(env, e->loc(),"not a string expression"); } break; case Expression::E_CALL: { Call* ce = e->cast(); if (ce->decl()==NULL) throw EvalError(env, e->loc(), "undeclared function", ce->id()); if (ce->decl()->_builtins.str) return ce->decl()->_builtins.str(env,ce); if (ce->decl()->_builtins.e) return eval_string(env,ce->decl()->_builtins.e(env,ce)); if (ce->decl()->e()==NULL) throw EvalError(env, ce->loc(), "internal error: missing builtin '"+ce->id().str()+"'"); return eval_call(env,ce); } break; case Expression::E_LET: { Let* l = e->cast(); l->pushbindings(); for (unsigned int i=0; ilet().size(); i++) { // Evaluate all variable declarations if (VarDecl* vdi = l->let()[i]->dyn_cast()) { vdi->e(eval_par(env, vdi->e())); if (vdi->ti()->domain()) { if (!checkParDomain(env, vdi->e(), vdi->ti()->domain())) { throw ResultUndefinedError(env, l->let()[i]->loc(),"domain constraint in let failed"); } } } else { // This is a constraint item. Since the let is par, // it can only be a par bool expression. If it evaluates // to false, it means that the value of this let is undefined. if (!eval_bool(env, l->let()[i])) { throw ResultUndefinedError(env, l->let()[i]->loc(),"constraint in let failed"); } } } std::string ret = eval_string(env,l->in()); l->popbindings(); return ret; } break; default: assert(false); return NULL; } } Expression* eval_par(EnvI& env, Expression* e) { if (e==NULL) return NULL; switch (e->eid()) { case Expression::E_ANON: case Expression::E_TIID: { return e; } case Expression::E_COMP: if (e->cast()->set()) return EvalSetLit::e(env,e); // fall through case Expression::E_ARRAYLIT: { ArrayLit* al = eval_array_lit(env,e); std::vector args(al->size()); for (unsigned int i=al->size(); i--;) args[i] = eval_par(env,(*al)[i]); std::vector > dims(al->dims()); for (unsigned int i=al->dims(); i--;) { dims[i].first = al->min(i); dims[i].second = al->max(i); } ArrayLit* ret = new ArrayLit(al->loc(),args,dims); Type t = al->type(); if (t.isbot() && ret->size() > 0) { t.bt((*ret)[0]->type().bt()); } ret->type(t); return ret; } case Expression::E_VARDECL: { VarDecl* vd = e->cast(); throw EvalError(env, vd->loc(),"cannot evaluate variable declaration", vd->id()->v()); } case Expression::E_TI: { TypeInst* t = e->cast(); ASTExprVec r; if (t->ranges().size() > 0) { std::vector rv(t->ranges().size()); for (unsigned int i=t->ranges().size(); i--;) rv[i] = static_cast(eval_par(env,t->ranges()[i])); r = ASTExprVec(rv); } return new TypeInst(Location(),t->type(),r,eval_par(env,t->domain())); } case Expression::E_ID: { if (e == constants().absent) return e; Id* id = e->cast(); if (id->decl()==NULL) throw EvalError(env, e->loc(),"undefined identifier", id->v()); if (id->decl()->ti()->domain()) { if (BoolLit* bl = id->decl()->ti()->domain()->dyn_cast()) return bl; if (id->decl()->ti()->type().isint()) { if (SetLit* sl = id->decl()->ti()->domain()->dyn_cast()) { if (sl->isv() && sl->isv()->min()==sl->isv()->max()) { return IntLit::a(sl->isv()->min()); } } } else if (id->decl()->ti()->type().isfloat()) { if (id->decl()->ti()->domain()) { FloatSetVal* fsv = eval_floatset(env, id->decl()->ti()->domain()); if (fsv->min() == fsv->max()) { return FloatLit::a(fsv->min()); } } } } if (id->decl()->e()==NULL) { return id; } else { return eval_par(env,id->decl()->e()); } } case Expression::E_STRINGLIT: return e; default: { if (e->type().dim() != 0) { ArrayLit* al = eval_array_lit(env,e); std::vector args(al->size()); for (unsigned int i=al->size(); i--;) args[i] = eval_par(env,(*al)[i]); std::vector > dims(al->dims()); for (unsigned int i=al->dims(); i--;) { dims[i].first = al->min(i); dims[i].second = al->max(i); } ArrayLit* ret = new ArrayLit(al->loc(),args,dims); Type t = al->type(); if ( (t.bt()==Type::BT_BOT || t.bt()==Type::BT_TOP) && ret->size() > 0) { t.bt((*ret)[0]->type().bt()); } ret->type(t); return ret; } if (e->type().ispar()) { if (e->type().is_set()) { return EvalSetLit::e(env,e); } if (e->type()==Type::parint()) { return EvalIntLit::e(env,e); } if (e->type()==Type::parbool()) { return EvalBoolLit::e(env,e); } if (e->type()==Type::parfloat()) { return EvalFloatLit::e(env,e); } if (e->type()==Type::parstring()) { return EvalStringLit::e(env,e); } } switch (e->eid()) { case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { if (ite->e_if(i)->type()==Type::parbool()) { if (eval_bool(env,ite->e_if(i))) return eval_par(env,ite->e_then(i)); } else { std::vector e_ifthen(ite->size()*2); for (int i=0; isize(); i++) { e_ifthen[2*i] = eval_par(env,ite->e_if(i)); e_ifthen[2*i+1] = eval_par(env,ite->e_then(i)); } ITE* n_ite = new ITE(ite->loc(),e_ifthen,eval_par(env,ite->e_else())); n_ite->type(ite->type()); return n_ite; } } return eval_par(env,ite->e_else()); } case Expression::E_CALL: { Call* c = e->cast(); if (c->decl()) { if (c->decl()->_builtins.e) { return eval_par(env,c->decl()->_builtins.e(env,c)); } else { if (c->decl()->e()==NULL) { if (c->id()=="deopt" && Expression::equal(c->arg(0),constants().absent)) throw ResultUndefinedError(env, e->loc(), "deopt(<>) is undefined"); return c; } return eval_call(env,c); } } else { std::vector args(c->n_args()); for (unsigned int i=0; iarg(i)); } Call* nc = new Call(c->loc(),c->id(),args); nc->type(c->type()); return nc; } } case Expression::E_BINOP: { BinOp* bo = e->cast(); BinOp* nbo = new BinOp(e->loc(),eval_par(env,bo->lhs()),bo->op(),eval_par(env,bo->rhs())); nbo->type(bo->type()); return nbo; } case Expression::E_UNOP: { UnOp* uo = e->cast(); UnOp* nuo = new UnOp(e->loc(),uo->op(),eval_par(env,uo->e())); nuo->type(uo->type()); return nuo; } case Expression::E_ARRAYACCESS: { ArrayAccess* aa = e->cast(); for (unsigned int i=0; iidx().size(); i++) { if (!aa->idx()[i]->type().ispar()) { std::vector idx(aa->idx().size()); for (unsigned int j=0; jidx().size(); j++) { idx[j] = eval_par(env, aa->idx()[j]); } ArrayAccess* aa_new = new ArrayAccess(e->loc(), eval_par(env, aa->v()),idx); aa_new->type(aa->type()); return aa_new; } } return eval_par(env,eval_arrayaccess(env,aa)); } default: return e; } } } } class ComputeIntBounds : public EVisitor { public: typedef std::pair Bounds; std::vector _bounds; bool valid; EnvI& env; ComputeIntBounds(EnvI& env0) : valid(true), env(env0) {} bool enter(Expression* e) { if (e->type().isann()) return false; if (e->isa()) return false; if (e->type().dim() > 0) return false; if (e->type().ispar()) { if (e->type().isint()) { IntVal v = eval_int(env,e); _bounds.push_back(Bounds(v,v)); } else { valid = false; } return false; } if (e->type().isint()) { if (ITE* ite = e->dyn_cast()) { Bounds itebounds(IntVal::infinity(), -IntVal::infinity()); for (int i=0; isize(); i++) { if (ite->e_if(i)->type().ispar() && ite->e_if(i)->type().cv()==Type::CV_NO) { if (eval_bool(env, ite->e_if(i))) { BottomUpIterator cbi(*this); cbi.run(ite->e_then(i)); Bounds& back = _bounds.back(); back.first = std::min(itebounds.first, back.first); back.second = std::max(itebounds.second, back.second); return false; } } else { BottomUpIterator cbi(*this); cbi.run(ite->e_then(i)); Bounds back = _bounds.back(); _bounds.pop_back(); itebounds.first = std::min(itebounds.first, back.first); itebounds.second = std::max(itebounds.second, back.second); } } BottomUpIterator cbi(*this); cbi.run(ite->e_else()); Bounds& back = _bounds.back(); back.first = std::min(itebounds.first, back.first); back.second = std::max(itebounds.second, back.second); return false; } return true; } return false; } /// Visit integer literal void vIntLit(const IntLit& i) { _bounds.push_back(Bounds(i.v(),i.v())); } /// Visit floating point literal void vFloatLit(const FloatLit&) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit Boolean literal void vBoolLit(const BoolLit&) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit set literal void vSetLit(const SetLit&) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit string literal void vStringLit(const StringLit&) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit identifier void vId(const Id& id) { VarDecl* vd = id.decl(); while (vd->flat() && vd->flat() != vd) vd = vd->flat(); if (vd->ti()->domain()) { GCLock lock; IntSetVal* isv = eval_intset(env,vd->ti()->domain()); if (isv->size()==0) { valid = false; _bounds.push_back(Bounds(0,0)); } else { _bounds.push_back(Bounds(isv->min(0),isv->max(isv->size()-1))); } } else { if (vd->e()) { BottomUpIterator cbi(*this); cbi.run(vd->e()); } else { _bounds.push_back(Bounds(-IntVal::infinity(),IntVal::infinity())); } } } /// Visit anonymous variable void vAnonVar(const AnonVar& v) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit array literal void vArrayLit(const ArrayLit& al) { } /// Visit array access void vArrayAccess(ArrayAccess& aa) { bool parAccess = true; for (unsigned int i=aa.idx().size(); i--;) { _bounds.pop_back(); if (!aa.idx()[i]->type().ispar()) { parAccess = false; } } if (Id* id = aa.v()->dyn_cast()) { while (id->decl()->e() && id->decl()->e()->isa()) { id = id->decl()->e()->cast(); } if (parAccess && id->decl()->e()) { bool success; Expression* e = eval_arrayaccess(env,&aa, success); if (success) { BottomUpIterator cbi(*this); cbi.run(e); return; } } if (id->decl()->ti()->domain()) { GCLock lock; IntSetVal* isv = eval_intset(env,id->decl()->ti()->domain()); if (isv->size()>0) { _bounds.push_back(Bounds(isv->min(0),isv->max(isv->size()-1))); return; } } } valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit array comprehension void vComprehension(const Comprehension& c) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit if-then-else void vITE(const ITE& ite) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit binary operator void vBinOp(const BinOp& bo) { Bounds b1 = _bounds.back(); _bounds.pop_back(); Bounds b0 = _bounds.back(); _bounds.pop_back(); if (!b1.first.isFinite() || !b1.second.isFinite() || !b0.first.isFinite() || !b0.second.isFinite()) { valid = false; _bounds.push_back(Bounds(0,0)); } else { switch (bo.op()) { case BOT_PLUS: _bounds.push_back(Bounds(b0.first+b1.first,b0.second+b1.second)); break; case BOT_MINUS: _bounds.push_back(Bounds(b0.first-b1.second,b0.second-b1.first)); break; case BOT_MULT: { IntVal x0 = b0.first*b1.first; IntVal x1 = b0.first*b1.second; IntVal x2 = b0.second*b1.first; IntVal x3 = b0.second*b1.second; IntVal m = std::min(x0,std::min(x1,std::min(x2,x3))); IntVal n = std::max(x0,std::max(x1,std::max(x2,x3))); _bounds.push_back(Bounds(m,n)); } break; case BOT_IDIV: { IntVal b0f = b0.first==0 ? 1 : b0.first; IntVal b0s = b0.second==0 ? -1 : b0.second; IntVal b1f = b1.first==0 ? 1 : b1.first; IntVal b1s = b1.second==0 ? -1 : b1.second; IntVal x0 = b0f / b1f; IntVal x1 = b0f / b1s; IntVal x2 = b0s / b1f; IntVal x3 = b0s / b1s; IntVal m = std::min(x0,std::min(x1,std::min(x2,x3))); IntVal n = std::max(x0,std::max(x1,std::max(x2,x3))); _bounds.push_back(Bounds(m,n)); } break; case BOT_MOD: { IntVal b0f = b0.first==0 ? 1 : b0.first; IntVal b0s = b0.second==0 ? -1 : b0.second; IntVal b1f = b1.first==0 ? 1 : b1.first; IntVal b1s = b1.second==0 ? -1 : b1.second; IntVal x0 = b0f % b1f; IntVal x1 = b0f % b1s; IntVal x2 = b0s % b1f; IntVal x3 = b0s % b1s; IntVal m = std::min(x0,std::min(x1,std::min(x2,x3))); IntVal n = std::max(x0,std::max(x1,std::max(x2,x3))); _bounds.push_back(Bounds(m,n)); } break; case BOT_POW: { IntVal exp_min = std::min(0,b1.first); IntVal exp_max = std::min(0,b1.second); IntVal x0 = b0.first.pow(exp_min); IntVal x1 = b0.first.pow(exp_max); IntVal x2 = b0.second.pow(exp_min); IntVal x3 = b0.second.pow(exp_max); IntVal m = std::min(x0,std::min(x1,std::min(x2,x3))); IntVal n = std::max(x0,std::max(x1,std::max(x2,x3))); _bounds.push_back(Bounds(m,n)); } break; case BOT_DIV: case BOT_LE: case BOT_LQ: case BOT_GR: case BOT_GQ: case BOT_EQ: case BOT_NQ: case BOT_IN: case BOT_SUBSET: case BOT_SUPERSET: case BOT_UNION: case BOT_DIFF: case BOT_SYMDIFF: case BOT_INTERSECT: case BOT_PLUSPLUS: case BOT_EQUIV: case BOT_IMPL: case BOT_RIMPL: case BOT_OR: case BOT_AND: case BOT_XOR: case BOT_DOTDOT: valid = false; _bounds.push_back(Bounds(0,0)); } } } /// Visit unary operator void vUnOp(const UnOp& uo) { switch (uo.op()) { case UOT_PLUS: break; case UOT_MINUS: _bounds.back().first = -_bounds.back().first; _bounds.back().second = -_bounds.back().second; std::swap(_bounds.back().first, _bounds.back().second); break; case UOT_NOT: valid = false; } } /// Visit call void vCall(Call& c) { if (c.id() == constants().ids.lin_exp || c.id() == constants().ids.sum) { bool le = c.id() == constants().ids.lin_exp; ArrayLit* coeff = le ? eval_array_lit(env,c.arg(0)): NULL; if (c.arg(le ? 1 : 0)->type().isopt()) { valid = false; _bounds.push_back(Bounds(0,0)); return; } ArrayLit* al = eval_array_lit(env,c.arg(le ? 1 : 0)); if (le) { _bounds.pop_back(); // remove constant (third arg) from stack } IntVal d = le ? c.arg(2)->cast()->v() : 0; int stacktop = static_cast(_bounds.size()); for (unsigned int i=al->size(); i--;) { BottomUpIterator cbi(*this); cbi.run((*al)[i]); if (!valid) { for (unsigned int j=al->size()-1; j>i; j--) _bounds.pop_back(); return; } } assert(stacktop+al->size()==_bounds.size()); IntVal lb = d; IntVal ub = d; for (unsigned int i=0; isize(); i++) { Bounds b = _bounds.back(); _bounds.pop_back(); IntVal cv = le ? eval_int(env,(*coeff)[i]) : 1; if (cv > 0) { if (b.first.isFinite()) { if (lb.isFinite()) { lb += cv*b.first; } } else { lb = b.first; } if (b.second.isFinite()) { if (ub.isFinite()) { ub += cv*b.second; } } else { ub = b.second; } } else { if (b.second.isFinite()) { if (lb.isFinite()) { lb += cv*b.second; } } else { lb = -b.second; } if (b.first.isFinite()) { if (ub.isFinite()) { ub += cv*b.first; } } else { ub = -b.first; } } } _bounds.push_back(Bounds(lb,ub)); } else if (c.id() == "card") { if (IntSetVal* isv = compute_intset_bounds(env,c.arg(0))) { IntSetRanges isr(isv); _bounds.push_back(Bounds(0,Ranges::cardinality(isr))); } else { valid = false; _bounds.push_back(Bounds(0,0)); } } else if (c.id() == "int_times") { Bounds b1 = _bounds.back(); _bounds.pop_back(); Bounds b0 = _bounds.back(); _bounds.pop_back(); if (!b1.first.isFinite() || !b1.second.isFinite() || !b0.first.isFinite() || !b0.second.isFinite()) { valid = false; _bounds.push_back(Bounds(0,0)); } else { IntVal x0 = b0.first*b1.first; IntVal x1 = b0.first*b1.second; IntVal x2 = b0.second*b1.first; IntVal x3 = b0.second*b1.second; IntVal m = std::min(x0,std::min(x1,std::min(x2,x3))); IntVal n = std::max(x0,std::max(x1,std::max(x2,x3))); _bounds.push_back(Bounds(m,n)); } } else if (c.id() == constants().ids.bool2int) { _bounds.push_back(Bounds(0,1)); } else if (c.id() == "abs") { Bounds b0 = _bounds.back(); if (b0.first < 0) { _bounds.pop_back(); if (b0.second < 0) _bounds.push_back(Bounds(-b0.second,-b0.first)); else _bounds.push_back(Bounds(0,std::max(-b0.first,b0.second))); } } else if (c.decl() && c.decl()->ti()->domain() && !c.decl()->ti()->domain()->isa()) { for (int i=0; itype().isint()) { assert(_bounds.size() > 0); _bounds.pop_back(); } } IntSetVal* isv = eval_intset(env, c.decl()->ti()->domain()); _bounds.push_back(Bounds(isv->min(),isv->max())); } else { valid = false; _bounds.push_back(Bounds(0,0)); } } /// Visit let void vLet(const Let& l) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit variable declaration void vVarDecl(const VarDecl& vd) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit annotation void vAnnotation(const Annotation& e) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit type inst void vTypeInst(const TypeInst& e) { valid = false; _bounds.push_back(Bounds(0,0)); } /// Visit TIId void vTIId(const TIId& e) { valid = false; _bounds.push_back(Bounds(0,0)); } }; IntBounds compute_int_bounds(EnvI& env, Expression* e) { try { ComputeIntBounds cb(env); BottomUpIterator cbi(cb); cbi.run(e); if (cb.valid) { assert(cb._bounds.size() == 1); return IntBounds(cb._bounds.back().first,cb._bounds.back().second,true); } else { return IntBounds(0,0,false); } } catch (ResultUndefinedError&) { return IntBounds(0,0,false); } } class ComputeFloatBounds : public EVisitor { protected: typedef std::pair FBounds; public: std::vector _bounds; bool valid; EnvI& env; ComputeFloatBounds(EnvI& env0) : valid(true), env(env0) {} bool enter(Expression* e) { if (e->type().isann()) return false; if (e->isa()) return false; if (e->type().dim() > 0) return false; if (e->type().ispar()) { if (e->type().isfloat()) { FloatVal v = eval_float(env,e); _bounds.push_back(FBounds(v,v)); } return false; } if (e->type().isfloat()) { if (ITE* ite = e->dyn_cast()) { FBounds itebounds(FloatVal::infinity(), -FloatVal::infinity()); for (int i=0; isize(); i++) { if (ite->e_if(i)->type().ispar() && ite->e_if(i)->type().cv()==Type::CV_NO) { if (eval_bool(env, ite->e_if(i))) { BottomUpIterator cbi(*this); cbi.run(ite->e_then(i)); FBounds& back = _bounds.back(); back.first = std::min(itebounds.first, back.first); back.second = std::max(itebounds.second, back.second); return false; } } else { BottomUpIterator cbi(*this); cbi.run(ite->e_then(i)); FBounds back = _bounds.back(); _bounds.pop_back(); itebounds.first = std::min(itebounds.first, back.first); itebounds.second = std::max(itebounds.second, back.second); } } BottomUpIterator cbi(*this); cbi.run(ite->e_else()); FBounds& back = _bounds.back(); back.first = std::min(itebounds.first, back.first); back.second = std::max(itebounds.second, back.second); return false; } return true; } return false; } /// Visit integer literal void vIntLit(const IntLit& i) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit floating point literal void vFloatLit(const FloatLit& f) { _bounds.push_back(FBounds(f.v(),f.v())); } /// Visit Boolean literal void vBoolLit(const BoolLit&) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit set literal void vSetLit(const SetLit&) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit string literal void vStringLit(const StringLit&) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit identifier void vId(const Id& id) { VarDecl* vd = id.decl(); while (vd->flat() && vd->flat() != vd) vd = vd->flat(); if (vd->ti()->domain()) { GCLock lock; FloatSetVal* fsv = eval_floatset(env,vd->ti()->domain()); if (fsv->size()==0) { valid = false; _bounds.push_back(FBounds(0,0)); } else { _bounds.push_back(FBounds(fsv->min(0),fsv->max(fsv->size()-1))); } } else { if (vd->e()) { BottomUpIterator cbi(*this); cbi.run(vd->e()); } else { _bounds.push_back(FBounds(-FloatVal::infinity(),FloatVal::infinity())); } } } /// Visit anonymous variable void vAnonVar(const AnonVar& v) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit array literal void vArrayLit(const ArrayLit& al) { } /// Visit array access void vArrayAccess(ArrayAccess& aa) { bool parAccess = true; for (unsigned int i=aa.idx().size(); i--;) { if (!aa.idx()[i]->type().ispar()) { parAccess = false; } } if (Id* id = aa.v()->dyn_cast()) { while (id->decl()->e() && id->decl()->e()->isa()) { id = id->decl()->e()->cast(); } if (parAccess && id->decl()->e()) { bool success; Expression* e = eval_arrayaccess(env,&aa, success); if (success) { BottomUpIterator cbi(*this); cbi.run(e); return; } } if (id->decl()->ti()->domain()) { FloatSetVal* fsv = eval_floatset(env, id->decl()->ti()->domain()); FBounds b(fsv->min(), fsv->max()); _bounds.push_back(b); return; } } valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit array comprehension void vComprehension(const Comprehension& c) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit if-then-else void vITE(const ITE& ite) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit binary operator void vBinOp(const BinOp& bo) { FBounds b1 = _bounds.back(); _bounds.pop_back(); FBounds b0 = _bounds.back(); _bounds.pop_back(); if (!b1.first.isFinite() || !b1.second.isFinite() || !b0.first.isFinite() || !b0.second.isFinite()) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } else { switch (bo.op()) { case BOT_PLUS: _bounds.push_back(FBounds(b0.first+b1.first,b0.second+b1.second)); break; case BOT_MINUS: _bounds.push_back(FBounds(b0.first-b1.second,b0.second-b1.first)); break; case BOT_MULT: { FloatVal x0 = b0.first*b1.first; FloatVal x1 = b0.first*b1.second; FloatVal x2 = b0.second*b1.first; FloatVal x3 = b0.second*b1.second; FloatVal m = std::min(x0,std::min(x1,std::min(x2,x3))); FloatVal n = std::max(x0,std::max(x1,std::max(x2,x3))); _bounds.push_back(FBounds(m,n)); } break; case BOT_POW: { FloatVal x0 = std::pow(b0.first.toDouble(),b1.first.toDouble()); FloatVal x1 = std::pow(b0.first.toDouble(),b1.second.toDouble()); FloatVal x2 = std::pow(b0.second.toDouble(),b1.first.toDouble()); FloatVal x3 = std::pow(b0.second.toDouble(),b1.second.toDouble()); FloatVal m = std::min(x0,std::min(x1,std::min(x2,x3))); FloatVal n = std::max(x0,std::max(x1,std::max(x2,x3))); _bounds.push_back(FBounds(m,n)); } break; case BOT_DIV: case BOT_IDIV: case BOT_MOD: case BOT_LE: case BOT_LQ: case BOT_GR: case BOT_GQ: case BOT_EQ: case BOT_NQ: case BOT_IN: case BOT_SUBSET: case BOT_SUPERSET: case BOT_UNION: case BOT_DIFF: case BOT_SYMDIFF: case BOT_INTERSECT: case BOT_PLUSPLUS: case BOT_EQUIV: case BOT_IMPL: case BOT_RIMPL: case BOT_OR: case BOT_AND: case BOT_XOR: case BOT_DOTDOT: valid = false; _bounds.push_back(FBounds(0.0,0.0)); } } } /// Visit unary operator void vUnOp(const UnOp& uo) { switch (uo.op()) { case UOT_PLUS: break; case UOT_MINUS: _bounds.back().first = -_bounds.back().first; _bounds.back().second = -_bounds.back().second; break; case UOT_NOT: valid = false; _bounds.push_back(FBounds(0.0,0.0)); } } /// Visit call void vCall(Call& c) { if (c.id() == constants().ids.lin_exp || c.id() == constants().ids.sum) { bool le = c.id() == constants().ids.lin_exp; ArrayLit* coeff = le ? eval_array_lit(env,c.arg(0)): NULL; if (le) { _bounds.pop_back(); // remove constant (third arg) from stack } if (c.arg(le ? 1 : 0)->type().isopt()) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); return; } ArrayLit* al = eval_array_lit(env,c.arg(le ? 1 : 0)); FloatVal d = le ? c.arg(2)->cast()->v() : 0.0; int stacktop = static_cast(_bounds.size()); for (unsigned int i=al->size(); i--;) { BottomUpIterator cbi(*this); cbi.run((*al)[i]); if (!valid) return; } assert(stacktop+al->size()==_bounds.size()); FloatVal lb = d; FloatVal ub = d; for (unsigned int i=0; i<(*al).size(); i++) { FBounds b = _bounds.back(); _bounds.pop_back(); FloatVal cv = le ? eval_float(env,(*coeff)[i]) : 1.0; if (cv > 0) { if (b.first.isFinite()) { if (lb.isFinite()) { lb += cv*b.first; } } else { lb = b.first; } if (b.second.isFinite()) { if (ub.isFinite()) { ub += cv*b.second; } } else { ub = b.second; } } else { if (b.second.isFinite()) { if (lb.isFinite()) { lb += cv*b.second; } } else { lb = -b.second; } if (b.first.isFinite()) { if (ub.isFinite()) { ub += cv*b.first; } } else { ub = -b.first; } } } _bounds.push_back(FBounds(lb,ub)); } else if (c.id() == "float_times") { BottomUpIterator cbi(*this); cbi.run(c.arg(0)); cbi.run(c.arg(1)); FBounds b1 = _bounds.back(); _bounds.pop_back(); FBounds b0 = _bounds.back(); _bounds.pop_back(); if (!b1.first.isFinite() || !b1.second.isFinite() || !b0.first.isFinite() || !b0.second.isFinite()) { valid = false; _bounds.push_back(FBounds(0,0)); } else { FloatVal x0 = b0.first*b1.first; FloatVal x1 = b0.first*b1.second; FloatVal x2 = b0.second*b1.first; FloatVal x3 = b0.second*b1.second; FloatVal m = std::min(x0,std::min(x1,std::min(x2,x3))); FloatVal n = std::max(x0,std::max(x1,std::max(x2,x3))); _bounds.push_back(FBounds(m,n)); } } else if (c.id() == "int2float") { ComputeIntBounds ib(env); BottomUpIterator cbi(ib); cbi.run(c.arg(0)); if (!ib.valid) valid = false; ComputeIntBounds::Bounds result = ib._bounds.back(); if (!result.first.isFinite() || !result.second.isFinite()) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } else { _bounds.push_back(FBounds(static_cast(result.first.toInt()),static_cast(result.second.toInt()))); } } else if (c.id() == "abs") { BottomUpIterator cbi(*this); cbi.run(c.arg(0)); FBounds b0 = _bounds.back(); if (b0.first < 0) { _bounds.pop_back(); if (b0.second < 0) _bounds.push_back(FBounds(-b0.second,-b0.first)); else _bounds.push_back(FBounds(0.0,std::max(-b0.first,b0.second))); } } else if (c.decl() && c.decl()->ti()->domain() && !c.decl()->ti()->domain()->isa()) { for (int i=0; itype().isfloat()) { assert(_bounds.size() > 0); _bounds.pop_back(); } } FloatSetVal* fsv = eval_floatset(env, c.decl()->ti()->domain()); _bounds.push_back(FBounds(fsv->min(),fsv->max())); } else { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } } /// Visit let void vLet(const Let& l) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit variable declaration void vVarDecl(const VarDecl& vd) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit annotation void vAnnotation(const Annotation& e) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit type inst void vTypeInst(const TypeInst& e) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } /// Visit TIId void vTIId(const TIId& e) { valid = false; _bounds.push_back(FBounds(0.0,0.0)); } }; FloatBounds compute_float_bounds(EnvI& env, Expression* e) { try { ComputeFloatBounds cb(env); BottomUpIterator cbi(cb); cbi.run(e); if (cb.valid) { assert(cb._bounds.size() > 0); return FloatBounds(cb._bounds.back().first,cb._bounds.back().second,true); } else { return FloatBounds(0.0,0.0,false); } } catch (ResultUndefinedError&) { return FloatBounds(0.0,0.0,false); } } class ComputeIntSetBounds : public EVisitor { public: std::vector _bounds; bool valid; EnvI& env; ComputeIntSetBounds(EnvI& env0) : valid(true), env(env0) {} bool enter(Expression* e) { if (e->type().isann()) return false; if (e->isa()) return false; if (e->type().dim() > 0) return false; if (!e->type().isintset()) return false; if (e->type().ispar()) { _bounds.push_back(eval_intset(env,e)); return false; } else { return true; } } /// Visit set literal void vSetLit(const SetLit& sl) { assert(sl.type().isvar()); assert(sl.isv()==NULL); IntSetVal* isv = IntSetVal::a(); for (unsigned int i=0; i cr(ib.l,ib.u); Ranges::Union > u(i0,cr); isv = IntSetVal::ai(u); } _bounds.push_back(isv); } /// Visit identifier void vId(const Id& id) { if (id.decl()->ti()->domain() && !id.decl()->ti()->domain()->isa()) { _bounds.push_back(eval_intset(env,id.decl()->ti()->domain())); } else { if (id.decl()->e()) { BottomUpIterator cbi(*this); cbi.run(id.decl()->e()); } else { valid = false; _bounds.push_back(NULL); } } } /// Visit anonymous variable void vAnonVar(const AnonVar& v) { valid = false; _bounds.push_back(NULL); } /// Visit array access void vArrayAccess(ArrayAccess& aa) { bool parAccess = true; for (unsigned int i=aa.idx().size(); i--;) { if (!aa.idx()[i]->type().ispar()) { parAccess = false; break; } } if (Id* id = aa.v()->dyn_cast()) { while (id->decl()->e() && id->decl()->e()->isa()) { id = id->decl()->e()->cast(); } if (parAccess && id->decl()->e()) { bool success; Expression* e = eval_arrayaccess(env,&aa, success); if (success) { BottomUpIterator cbi(*this); cbi.run(e); return; } } if (id->decl()->ti()->domain()) { _bounds.push_back(eval_intset(env,id->decl()->ti()->domain())); return; } } valid = false; _bounds.push_back(NULL); } /// Visit array comprehension void vComprehension(const Comprehension& c) { valid = false; _bounds.push_back(NULL); } /// Visit if-then-else void vITE(const ITE& ite) { valid = false; _bounds.push_back(NULL); } /// Visit binary operator void vBinOp(const BinOp& bo) { if (bo.op()==BOT_DOTDOT) { IntBounds lb = compute_int_bounds(env, bo.lhs()); IntBounds ub = compute_int_bounds(env, bo.rhs()); valid = valid && lb.valid && ub.valid; _bounds.push_back(IntSetVal::a(lb.l, ub.u)); } else { IntSetVal* b1 = _bounds.back(); _bounds.pop_back(); IntSetVal* b0 = _bounds.back(); _bounds.pop_back(); switch (bo.op()) { case BOT_INTERSECT: case BOT_UNION: { IntSetRanges b0r(b0); IntSetRanges b1r(b1); Ranges::Union u(b0r,b1r); _bounds.push_back(IntSetVal::ai(u)); } break; case BOT_DIFF: { _bounds.push_back(b0); } break; case BOT_SYMDIFF: valid = false; _bounds.push_back(NULL); break; case BOT_PLUS: case BOT_MINUS: case BOT_MULT: case BOT_POW: case BOT_DIV: case BOT_IDIV: case BOT_MOD: case BOT_LE: case BOT_LQ: case BOT_GR: case BOT_GQ: case BOT_EQ: case BOT_NQ: case BOT_IN: case BOT_SUBSET: case BOT_SUPERSET: case BOT_PLUSPLUS: case BOT_EQUIV: case BOT_IMPL: case BOT_RIMPL: case BOT_OR: case BOT_AND: case BOT_XOR: case BOT_DOTDOT: valid = false; _bounds.push_back(NULL); } } } /// Visit unary operator void vUnOp(const UnOp& uo) { valid = false; _bounds.push_back(NULL); } /// Visit call void vCall(Call& c) { if (valid && (c.id() == "set_intersect" || c.id() == "set_union")) { IntSetVal* b0 = _bounds.back(); _bounds.pop_back(); IntSetVal* b1 = _bounds.back(); _bounds.pop_back(); IntSetRanges b0r(b0); IntSetRanges b1r(b1); Ranges::Union u(b0r,b1r); _bounds.push_back(IntSetVal::ai(u)); } else if (valid && c.id() == "set_diff") { IntSetVal* b0 = _bounds.back(); _bounds.pop_back(); _bounds.pop_back(); // don't need bounds of right hand side _bounds.push_back(b0); } else if (c.decl() && c.decl()->ti()->domain() && !c.decl()->ti()->domain()->isa()) { for (int i=0; itype().isintset()) { assert(_bounds.size() > 0); _bounds.pop_back(); } } IntSetVal* fsv = eval_intset(env, c.decl()->ti()->domain()); _bounds.push_back(fsv); } else { valid = false; _bounds.push_back(NULL); } } /// Visit let void vLet(const Let& l) { valid = false; _bounds.push_back(NULL); } /// Visit variable declaration void vVarDecl(const VarDecl& vd) { valid = false; _bounds.push_back(NULL); } /// Visit annotation void vAnnotation(const Annotation& e) { valid = false; _bounds.push_back(NULL); } /// Visit type inst void vTypeInst(const TypeInst& e) { valid = false; _bounds.push_back(NULL); } /// Visit TIId void vTIId(const TIId& e) { valid = false; _bounds.push_back(NULL); } }; IntSetVal* compute_intset_bounds(EnvI& env, Expression* e) { try { ComputeIntSetBounds cb(env); BottomUpIterator cbi(cb); cbi.run(e); if (cb.valid) return cb._bounds.back(); else return NULL; } catch (ResultUndefinedError&) { return NULL; } } Expression* follow_id(Expression* e) { for (;;) { if (e==NULL) return NULL; if (e->eid()==Expression::E_ID && e != constants().absent) { e = e->cast()->decl()->e(); } else { return e; } } } Expression* follow_id_to_decl(Expression* e) { for (;;) { if (e==NULL) return NULL; if (e==constants().absent) return e; switch (e->eid()) { case Expression::E_ID: e = e->cast()->decl(); break; case Expression::E_VARDECL: if (e->cast()->e() && e->cast()->e()->isa()) e = e->cast()->e(); else return e; break; default: return e; } } } Expression* follow_id_to_value(Expression* e) { Expression* decl = follow_id_to_decl(e); if (VarDecl* vd = decl->dyn_cast()) { if (vd->e() && vd->e()->type().ispar()) return vd->e(); return vd->id(); } else { return decl; } } } libminizinc-2.4.2/lib/file_utils.cpp000066400000000000000000000444671360574160400174640ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #include #include #include #include #include #include #ifdef HAS_PIDPATH #include #include #include #include #include #elif defined(HAS_GETMODULEFILENAME) || defined(HAS_GETFILEATTRIBUTES) #include #else #include #endif #include #include #ifdef _MSC_VER #include "Shlwapi.h" #pragma comment(lib, "Shlwapi.lib") #include "Shlobj.h" #include #else #include #include #include #endif namespace MiniZinc { namespace FileUtils { #ifdef HAS_PIDPATH std::string progpath(void) { pid_t pid = getpid(); char path[PROC_PIDPATHINFO_MAXSIZE]; int ret = proc_pidpath (pid, path, sizeof(path)); if ( ret <= 0 ) { return ""; } else { std::string p(path); size_t slash = p.find_last_of("/"); if (slash != std::string::npos) { p = p.substr(0,slash); } return p; } } #elif defined(HAS_GETMODULEFILENAME) std::string progpath(void) { char path[MAX_PATH]; int ret = GetModuleFileName(NULL, path, MAX_PATH); if ( ret <= 0 ) { return ""; } else { std::string p(path); size_t slash = p.find_last_of("/\\"); if (slash != std::string::npos) { p = p.substr(0,slash); } return p; } } #else std::string progpath(void) { const int bufsz = 2000; char path[bufsz+1]; ssize_t sz = readlink("/proc/self/exe", path, bufsz); if ( sz < 0 ) { return ""; } else { path[sz] = '\0'; std::string p(path); size_t slash = p.find_last_of("/"); if (slash != std::string::npos) { p = p.substr(0,slash); } return p; } } #endif bool file_exists(const std::string& filename) { #if defined(HAS_GETFILEATTRIBUTES) DWORD dwAttrib = GetFileAttributes(filename.c_str()); return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); #else struct stat info; return stat(filename.c_str(), &info)==0 && (info.st_mode & S_IFREG); #endif } bool directory_exists(const std::string& dirname) { #if defined(HAS_GETFILEATTRIBUTES) DWORD dwAttrib = GetFileAttributes(dirname.c_str()); return (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); #else struct stat info; return stat(dirname.c_str(), &info)==0 && (info.st_mode & S_IFDIR); #endif } std::string file_path(const std::string& filename, const std::string& basePath) { #ifdef _MSC_VER LPSTR lpBuffer, lpFilePart; DWORD nBufferLength = GetFullPathName(filename.c_str(), 0,0,&lpFilePart); if (!(lpBuffer = (LPTSTR)LocalAlloc(LMEM_FIXED, sizeof(TCHAR) * nBufferLength))) return 0; std::string ret; DWORD error = GetFullPathName(filename.c_str(), nBufferLength, lpBuffer, &lpFilePart); DWORD fileAttr = GetFileAttributes(lpBuffer); DWORD lastError = GetLastError(); if(error == 0 || (fileAttr == INVALID_FILE_ATTRIBUTES && lastError != NO_ERROR)) { if (basePath.empty()) ret = filename; else ret = file_path(basePath+"/"+filename); } else { ret = std::string(lpBuffer); } LocalFree(lpBuffer); return ret; #else char* rp = realpath(filename.c_str(), NULL); if (rp==NULL) { if (basePath.empty()) return filename; else return file_path(basePath+"/"+filename); } std::string rp_s(rp); free(rp); return rp_s; #endif } std::string dir_name(const std::string& filename) { #ifdef _MSC_VER size_t pos = filename.find_last_of("\\/"); return (pos==std::string::npos) ? "" : filename.substr(0,pos); #else char* fn = strdup(filename.c_str()); char* dn = dirname(fn); std::string ret(dn); free(fn); return ret; #endif } std::string base_name(const std::string& filename) { #ifdef _MSC_VER size_t pos = filename.find_last_of("\\/"); return (pos==std::string::npos) ? filename : filename.substr(pos+1); #else char* fn = strdup(filename.c_str()); char* dn = basename(fn); std::string ret(dn); free(fn); return ret; #endif } bool is_absolute(const std::string& path) { #ifdef _MSC_VER if (path.size() > 2 && ((path[0]=='\\' && path[1]=='\\') || (path[0] == '/' && path[1] == '/'))) return true; return !PathIsRelative(path.c_str()); #else return path.empty() ? false : (path[0]=='/'); #endif } std::string find_executable(const std::string& filename) { if (is_absolute(filename)) { if (file_exists(filename)) { return filename; } #ifdef _MSC_VER if (FileUtils::file_exists(filename+".exe")) { return filename+".exe"; } else if (FileUtils::file_exists(filename+".bat")) { return filename+".bat"; } #endif return ""; } char* path_c = getenv("PATH"); #ifdef _MSC_VER char pathsep = ';'; #else char pathsep = ':'; #endif std::string path; if (path_c) { path = path_c; if (path.size()) { path += pathsep; } } path += progpath(); std::string pathItem; std::stringstream pathStream(path); while (std::getline(pathStream, pathItem, pathsep)) { std::string fileWithPath = pathItem+"/"+filename; if (file_exists(fileWithPath)) return fileWithPath; #ifdef _MSC_VER if (FileUtils::file_exists(fileWithPath+".exe")) { return fileWithPath+".exe"; } else if (FileUtils::file_exists(fileWithPath+".bat")) { return fileWithPath+".bat"; } #endif } return ""; } std::vector directory_list(const std::string& dir, const std::string& ext) { std::vector entries; #ifdef _MSC_VER WIN32_FIND_DATA findData; HANDLE hFind = ::FindFirstFile( (dir+"/*."+ext).c_str(), &findData); if (hFind != INVALID_HANDLE_VALUE) { do { if ( !(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) { entries.push_back(findData.cFileName); } } while(::FindNextFile(hFind, &findData)); ::FindClose(hFind); } #else DIR* dirp = opendir(dir.c_str()); if (dirp) { struct dirent* dp; while ((dp = readdir(dirp)) != NULL) { std::string fileName(dp->d_name); struct stat info; if (stat( (dir+"/"+fileName).c_str(), &info)==0 && (info.st_mode & S_IFREG)) { if (ext=="*") { entries.push_back(fileName); } else { if (fileName.size() > ext.size()+2 && fileName.substr(fileName.size()-ext.size()-1)=="."+ext) { entries.push_back(fileName); } } } } closedir(dirp); } #endif return entries; } std::string working_directory(void) { char wd[FILENAME_MAX]; #ifdef _MSC_VER if (!_getcwd(wd,sizeof(wd))) return ""; #else if (!getcwd(wd,sizeof(wd))) return ""; #endif return wd; } std::string share_directory(void) { if (char* MZNSTDLIBDIR = getenv("MZN_STDLIB_DIR")) { return std::string(MZNSTDLIBDIR); } std::string mypath = FileUtils::progpath(); int depth = 0; for (unsigned int i=0; i 0) { char* tmp = new char[charsRequired]; if (WideCharToMultiByte(CP_ACP, 0, pszPath, -1, tmp, charsRequired, 0, 0) != 0) { tmp[charsRequired-1]=0; configPath=tmp; } delete[] tmp; } CoTaskMemFree(pszPath); if (configPath.empty()) { return ""; } else { return configPath+"/MiniZinc"; } } return ""; #else if (const char* hd = getenv("HOME")) { return std::string(hd)+"/.minizinc"; } return ""; #endif } std::string global_config_file(void) { std::string sd = share_directory(); if (sd.empty()) return ""; return sd+"/Preferences.json"; } std::string user_config_file(void) { return user_config_dir()+"/Preferences.json"; } TmpFile::TmpFile(const std::string& ext) { #ifdef _WIN32 TCHAR szTempFileName[MAX_PATH]; TCHAR lpTempPathBuffer[MAX_PATH]; bool didCopy; do { GetTempPath(MAX_PATH, lpTempPathBuffer); GetTempFileName(lpTempPathBuffer, "tmp_mzn_", 0, szTempFileName); _name = szTempFileName; _tmpNames.push_back(_name); didCopy = CopyFile(_name.c_str(), (_name + ext).c_str(), true); } while (!didCopy); _name += ext; #else _tmpfile_desc = -1; _name = "/tmp/mznfileXXXXXX"+ext; char* tmpfile = strndup(_name.c_str(), _name.size()); _tmpfile_desc = mkstemps(tmpfile, ext.size()); if (_tmpfile_desc == -1) { ::free(tmpfile); throw InternalError("Error occurred when creating temporary file"); } _name = std::string(tmpfile); ::free(tmpfile); #endif } TmpFile::~TmpFile(void) { remove(_name.c_str()); #ifdef _WIN32 for (auto& n : _tmpNames) { remove(n.c_str()); } #endif #ifndef _WIN32 if (_tmpfile_desc != -1) close(_tmpfile_desc); #endif } TmpDir::TmpDir(void) { #ifdef _WIN32 TCHAR szTempFileName[MAX_PATH]; TCHAR lpTempPathBuffer[MAX_PATH]; GetTempPath(MAX_PATH, lpTempPathBuffer); GetTempFileName(lpTempPathBuffer, "tmp_mzn_", 0, szTempFileName); _name = szTempFileName; DeleteFile(_name.c_str()); CreateDirectory(_name.c_str(),NULL); #else _name = "/tmp/mzndirXXXXXX"; char* tmpfile = strndup(_name.c_str(), _name.size()); if (mkdtemp(tmpfile) == NULL) { ::free(tmpfile); throw InternalError("Error occurred when creating temporary directory"); } _name = std::string(tmpfile); ::free(tmpfile); #endif } #ifdef _WIN32 namespace { void remove_dir(const std::string& d) { HANDLE dh; WIN32_FIND_DATA info; std::string pattern = d+"\\*.*"; dh = ::FindFirstFile(pattern.c_str(), &info); if (dh != INVALID_HANDLE_VALUE) { do { if (info.cFileName[0] != '.') { std::string fp = d+"\\"+info.cFileName; if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { remove_dir(fp); } else { ::SetFileAttributes(fp.c_str(), FILE_ATTRIBUTE_NORMAL); ::DeleteFile(fp.c_str()); } } } while (::FindNextFile(dh, &info) == TRUE); } ::FindClose(dh); ::SetFileAttributes(d.c_str(), FILE_ATTRIBUTE_NORMAL); ::RemoveDirectory(d.c_str()); } } #else namespace { int remove_file(const char *fpath, const struct stat *, int, struct FTW *) { return unlink(fpath); } } #endif TmpDir::~TmpDir(void) { #ifdef _WIN32 remove_dir(_name); #else nftw(_name.c_str(), remove_file, 64, FTW_DEPTH | FTW_PHYS); rmdir(_name.c_str()); #endif } std::vector parseCmdLine(const std::string& s) { // Break the string up at whitespace, except inside quotes, but ignore escaped quotes std::vector c; size_t cur = 0; size_t l = s.length(); std::ostringstream oss; bool inside_quote = false; bool had_escape = false; for (; cur < l; cur++) { if (inside_quote) { if (s[cur]=='"') { if (had_escape) { oss << "\""; had_escape = false; } else { inside_quote = false; } } else if (s[cur]=='\\') { had_escape = true; } else { if (had_escape) { oss << "\\"; had_escape = false; } oss << s[cur]; } } else { if (s[cur]==' ') { if (had_escape) { oss << " "; had_escape = false; } else { c.push_back(oss.str()); oss.str(std::string()); } } else if (s[cur]=='\\') { if (had_escape) { oss << "\\"; had_escape = false; } else { had_escape = true; } } else if (s[cur]=='"') { if (had_escape) { oss << "\""; had_escape = false; } else { inside_quote = true; } } else { if (had_escape) { switch (s[cur]) { case 'a' : oss << "\a"; break; case 'b' : oss << "\b"; break; case 'f' : oss << "\f"; break; case 'n' : oss << "\n"; break; case 'r' : oss << "\r"; break; case 't' : oss << "\t"; break; case 'v' : oss << "\v"; break; default: oss << "\\" << s[cur]; break; } had_escape = false; } else { oss << s[cur]; } } } } c.push_back(oss.str()); return c; } std::string combineCmdLine(const std::vector& cmd) { std::ostringstream ret; for (unsigned int i=0; i(&s[0]); // autodetect compressed string if (s.size() >= 2 && ((cc[0] == 0x1F && cc[1] == 0x8B) // gzip || (cc[0] == 0x78 && (cc[1] == 0x01 // zlib || cc[1] == 0x9C || cc[1] == 0xDA)))) { const int BUF_SIZE=1024; unsigned char s_outbuf[BUF_SIZE]; z_stream stream; std::memset(&stream, 0, sizeof(stream)); unsigned char* dataStart; int windowBits; size_t dataLen; if (cc[0]==0x1F && cc[1]==0x8B) { dataStart = cc+10; windowBits = -Z_DEFAULT_WINDOW_BITS; if (cc[3] & 0x4) { dataStart += 2; if (dataStart >= cc+s.size()) throw(-1); } if (cc[3] & 0x8) { while (*dataStart != '\0') { dataStart++; if (dataStart >= cc+s.size()) throw(-1); } dataStart++; if (dataStart >= cc+s.size()) throw(-1); } if (cc[3] & 0x10) { while (*dataStart != '\0') { dataStart++; if (dataStart >= cc+s.size()) throw(-1); } dataStart++; if (dataStart >= cc+s.size()) throw(-1); } if (cc[3] & 0x2) { dataStart += 2; if (dataStart >= cc+s.size()) throw(-1); } dataLen = s.size() - (dataStart-cc); } else { dataStart = cc; windowBits = Z_DEFAULT_WINDOW_BITS; dataLen = s.size(); } stream.next_in = dataStart; stream.avail_in = static_cast(dataLen); stream.next_out = &s_outbuf[0]; stream.avail_out = BUF_SIZE; int status = inflateInit2(&stream, windowBits); if (status != Z_OK) throw(status); std::ostringstream oss; while (true) { status = inflate(&stream, Z_NO_FLUSH); if (status == Z_STREAM_END || !stream.avail_out) { // output buffer full or compression finished oss << std::string(reinterpret_cast(s_outbuf),BUF_SIZE - stream.avail_out); stream.next_out = &s_outbuf[0]; stream.avail_out = BUF_SIZE; } if (status == Z_STREAM_END) break; if (status != Z_OK) throw(status); } status = inflateEnd(&stream); if (status != Z_OK) throw(status); s = oss.str(); } } std::string deflateString(const std::string& s) { mz_ulong compressedLength = compressBound(static_cast(s.size())); unsigned char* cmpr = static_cast(::malloc(compressedLength*sizeof(unsigned char))); int status = compress(cmpr,&compressedLength,reinterpret_cast(&s[0]),static_cast(s.size())); if (status != Z_OK) { ::free(cmpr); throw(status); } std::string ret(reinterpret_cast(cmpr),compressedLength); ::free(cmpr); return ret; } std::string encodeBase64(const std::string& s) { base64::encoder E; std::ostringstream oss; oss << "@"; // add leading "@" to distinguish from valid MiniZinc code std::istringstream iss(s); E.encode(iss, oss); return oss.str(); } std::string decodeBase64(const std::string& s) { if (s.size()==0 || s[0] != '@') throw InternalError("string is not base64 encoded"); base64::decoder D; std::ostringstream oss; std::istringstream iss(s); (void) iss.get(); // remove leading "@" D.decode(iss, oss); return oss.str(); } }} libminizinc-2.4.2/lib/flatten.cpp000066400000000000000000004527721360574160400167640ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include #include #include #include #include #include #include #include namespace MiniZinc { // Create domain constraints. Return true if successful. bool createExplicitDomainConstraints(EnvI& envi, VarDecl* vd, Expression* domain) { std::vector calls; Location iloc = Location().introduce(); if(domain->type().isfloat() || domain->type().isfloatset()) { FloatSetVal* fsv = eval_floatset(envi, domain); if(fsv->size() == 1) { // Range based if(fsv->min() == fsv->max()) { calls.push_back(new Call(iloc, constants().ids.float_.eq, {vd->id(), FloatLit::a(fsv->min())})); } else { FloatSetVal* cfsv; if(vd->ti()->domain()) { cfsv = eval_floatset(envi, vd->ti()->domain()); } else { cfsv = FloatSetVal::a(-FloatVal::infinity(), FloatVal::infinity()); } if(cfsv->min() < fsv->min()) { calls.push_back(new Call(iloc, constants().ids.float_.le, {FloatLit::a(fsv->min()), vd->id()})); } if(cfsv->max() > fsv->max()) { calls.push_back(new Call(iloc, constants().ids.float_.le, {vd->id(), FloatLit::a(fsv->max())})); } } } else { calls.push_back(new Call(iloc, constants().ids.set_in, {vd->id(), new SetLit(iloc, fsv)})); } } else if(domain->type().isint() || domain->type().isintset()) { IntSetVal* isv = eval_intset(envi, domain); if(isv->size() == 1) { // Range based if(isv->min() == isv->max()) { calls.push_back(new Call(iloc, constants().ids.int_.eq, {vd->id(), IntLit::a(isv->min())})); } else { IntSetVal* cisv; if(vd->ti()->domain()) { cisv = eval_intset(envi, vd->ti()->domain()); } else { cisv = IntSetVal::a(-IntVal::infinity(), IntVal::infinity()); } if(cisv->min() < isv->min()) { calls.push_back(new Call(iloc, constants().ids.int_.le, {IntLit::a(isv->min()), vd->id()})); } if(cisv->max() > isv->max()) { calls.push_back(new Call(iloc, constants().ids.int_.le, {vd->id(), IntLit::a(isv->max())})); } } } else { calls.push_back(new Call(iloc, constants().ids.set_in, {vd->id(), new SetLit(iloc, isv)})); } } else { std::cerr << "Warning: domain change not handled by -g mode: " << *vd->id() << " = " << *domain << std::endl; return false; } int counter = 0; for (Call* c : calls) { CallStackItem csi(envi, IntLit::a(counter++)); c->ann().add(constants().ann.domain_change_constraint); c->type(Type::varbool()); c->decl(envi.model->matchFn(envi, c, true)); flat_exp(envi, Ctx(), c, constants().var_true, constants().var_true); } return true; } void setComputedDomain(EnvI& envi, VarDecl* vd, Expression* domain, bool is_computed) { if (!envi.fopts.record_domain_changes || vd->ann().contains(constants().ann.is_defined_var) || vd->introduced() || !createExplicitDomainConstraints(envi, vd, domain)) { vd->ti()->domain(domain); vd->ti()->setComputedDomain(is_computed); } } /// Output operator for contexts template std::basic_ostream& operator <<(std::basic_ostream& os, Ctx& ctx) { switch (ctx.b) { case C_ROOT: os << "R"; break; case C_POS: os << "+"; break; case C_NEG: os << "-"; break; case C_MIX: os << "M"; break; default: assert(false); break; } switch (ctx.i) { case C_ROOT: os << "R"; break; case C_POS: os << "+"; break; case C_NEG: os << "-"; break; case C_MIX: os << "M"; break; default: assert(false); break; } if (ctx.neg) os << "!"; return os; } BCtx operator +(const BCtx& c) { switch (c) { case C_ROOT: return C_POS; case C_POS: return C_POS; case C_NEG: return C_NEG; case C_MIX: return C_MIX; default: assert(false); return C_ROOT; } } BCtx operator -(const BCtx& c) { switch (c) { case C_ROOT: return C_NEG; case C_POS: return C_NEG; case C_NEG: return C_POS; case C_MIX: return C_MIX; default: assert(false); return C_ROOT; } } /// Check if \a c is non-positive bool nonpos(const BCtx& c) { return c==C_NEG || c==C_MIX; } /// Check if \a c is non-negative bool nonneg(const BCtx& c) { return c==C_ROOT || c==C_POS; } void dumpEEb(const std::vector& ee) { for (unsigned int i=0; i& ee) { for (unsigned int i=0; i ann2Ctx(VarDecl* vd) { if (vd->ann().contains(constants().ctx.root)) { return std::make_tuple(C_ROOT, true); } else if (vd->ann().contains(constants().ctx.mix)) { return std::make_tuple(C_MIX, true); } else if (vd->ann().contains(constants().ctx.pos)) { return std::make_tuple(C_POS, true); } else if (vd->ann().contains(constants().ctx.neg)) { return std::make_tuple(C_NEG, true); } else { return std::make_tuple(C_MIX, false); } } void addCtxAnn(VarDecl* vd, BCtx& c) { if (vd) { Id* ctx_id = NULL; BCtx nc; bool annotated; std::tie(nc, annotated) = ann2Ctx(vd); // If previously annotated if (annotated) { // Early exit if (nc == c || nc == C_ROOT || (nc == C_MIX && c != C_ROOT)){ return; } // Remove old annotation switch (nc) { case C_ROOT: vd->ann().remove(constants().ctx.root); break; case C_MIX: vd->ann().remove(constants().ctx.mix); break; case C_POS: vd->ann().remove(constants().ctx.pos); break; case C_NEG: vd->ann().remove(constants().ctx.neg); break; default: assert(false); break; } // Determine new context if (c == C_ROOT) { nc = C_ROOT; } else { nc = C_MIX; } } else { nc = c; } switch (nc) { case C_ROOT: ctx_id=constants().ctx.root; break; case C_POS: ctx_id=constants().ctx.pos; break; case C_NEG: ctx_id=constants().ctx.neg; break; case C_MIX: ctx_id=constants().ctx.mix; break; default: assert(false); break; } vd->addAnnotation(ctx_id); } } void makeDefinedVar(VarDecl* vd, Call* c) { if (!vd->ann().contains(constants().ann.is_defined_var)) { std::vector args(1); args[0] = vd->id(); Call* dv = new Call(Location().introduce(),constants().ann.defines_var,args); dv->type(Type::ann()); vd->addAnnotation(constants().ann.is_defined_var); c->addAnnotation(dv); } } bool isDefinesVarAnn(Expression* e) { return e->isa() && e->cast()->id()==constants().ann.defines_var; } /// Check if \a e is NULL or true bool istrue(EnvI& env, Expression* e) { GCLock lock; return e==NULL || (e->type().ispar() && e->type().isbool() && eval_bool(env,e)); } /// Check if \a e is non-NULL and false bool isfalse(EnvI& env, Expression* e) { GCLock lock; return e!=NULL && e->type().ispar() && e->type().isbool() && !eval_bool(env,e); } EE flat_exp(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b); KeepAlive bind(EnvI& env, Ctx ctx, VarDecl* vd, Expression* e); /// Use bounds from ovd for vd if they are better. /// Returns true if ovd's bounds are better. bool updateBounds(EnvI& envi, VarDecl* ovd, VarDecl* vd) { bool tighter = false; bool fixed = false; if(ovd->ti()->domain() || ovd->e()) { IntVal intval; FloatVal doubleval; bool boolval; if(vd->type().isint()) { IntBounds oldbounds = compute_int_bounds(envi, ovd->id()); IntBounds bounds(0,0,false); if(vd->ti()->domain() || vd->e()) bounds = compute_int_bounds(envi, vd->id()); if((vd->ti()->domain() || vd->e()) && bounds.valid && bounds.l.isFinite() && bounds.u.isFinite()) { if(oldbounds.valid && oldbounds.l.isFinite() && oldbounds.u.isFinite()) { fixed = oldbounds.u == oldbounds.l || bounds.u == bounds.l; if(fixed) { tighter = true; intval = oldbounds.u == oldbounds.l ? oldbounds.u : bounds.l; ovd->ti()->domain(new SetLit(ovd->loc(), IntSetVal::a(intval, intval))); } else { IntSetVal* olddom = ovd->ti()->domain() ? eval_intset(envi, ovd->ti()->domain()) : NULL; IntSetVal* newdom = vd->ti()->domain() ? eval_intset(envi, vd->ti()->domain()) : NULL; if(olddom) { if(!newdom) { tighter = true; } else { IntSetRanges oisr(olddom); IntSetRanges nisr(newdom); IntSetRanges nisr_card(newdom); Ranges::Inter inter(oisr, nisr); if(Ranges::cardinality(inter) < Ranges::cardinality(nisr_card)) { IntSetRanges oisr_inter(olddom); IntSetRanges nisr_inter(newdom); Ranges::Inter inter_card(oisr_inter, nisr_inter); tighter = true; ovd->ti()->domain(new SetLit(ovd->loc(), IntSetVal::ai(inter_card))); } } } } } } else { if(oldbounds.valid && oldbounds.l.isFinite() && oldbounds.u.isFinite()) { tighter = true; fixed = oldbounds.u == oldbounds.l; if(fixed) { intval = oldbounds.u; ovd->ti()->domain(new SetLit(ovd->loc(), IntSetVal::a(intval, intval))); } } } } else if(vd->type().isfloat()) { FloatBounds oldbounds = compute_float_bounds(envi, ovd->id()); FloatBounds bounds(0.0, 0.0, false); if(vd->ti()->domain() || vd->e()) bounds = compute_float_bounds(envi, vd->id()); if((vd->ti()->domain() || vd->e()) && bounds.valid) { if(oldbounds.valid) { fixed = oldbounds.u == oldbounds.l || bounds.u == bounds.l; if(fixed) doubleval = oldbounds.u == oldbounds.l ? oldbounds.u : bounds.l; tighter = fixed || (oldbounds.u - oldbounds.l < bounds.u - bounds.l); } } else { if(oldbounds.valid) { tighter = true; fixed = oldbounds.u == oldbounds.l; if(fixed) doubleval = oldbounds.u; } } } else if(vd->type().isbool()) { if(ovd->ti()->domain()) { fixed = tighter = true; boolval = eval_bool(envi, ovd->ti()->domain()); } else { fixed = tighter = (ovd->e() && ovd->e()->isa()); if(fixed) boolval = ovd->e()->cast()->v(); } } if(tighter) { vd->ti()->domain(ovd->ti()->domain()); if(vd->e() == NULL && fixed) { if(vd->ti()->type().isvarint()) { vd->type(Type::parint()); vd->ti(new TypeInst(vd->loc(), Type::parint())); vd->e(IntLit::a(intval)); } else if(vd->ti()->type().isvarfloat()) { vd->type(Type::parfloat()); vd->ti(new TypeInst(vd->loc(), Type::parfloat())); vd->e(FloatLit::a(doubleval)); } else if(vd->ti()->type().isvarbool()) { vd->type(Type::parbool()); vd->ti(new TypeInst(vd->loc(), Type::parbool())); vd->ti()->domain(boolval ? constants().lit_true : constants().lit_false); vd->e(new BoolLit(vd->loc(), boolval)); } } } } return tighter; } std::string getPath(EnvI& env) { std::string path; std::stringstream ss; if(env.dumpPath(ss)) path = ss.str(); return path; } inline Location getLoc(EnvI& env, Expression* e1, Expression* e2) { if(e1) { return e1->loc().introduce(); } else if(e2) { return e2->loc().introduce(); } else { return Location().introduce(); } } inline Id* getId(EnvI& env, Id* origId) { return origId ? origId : new Id(Location().introduce(),env.genId(), NULL); } StringLit* getLongestMznPathAnnotation(EnvI& env, const Expression* e) { StringLit* sl = NULL; if(const VarDecl* vd = e->dyn_cast()) { EnvI::ReversePathMap& reversePathMap = env.getReversePathMap(); KeepAlive vd_decl_ka (vd->id()->decl()); EnvI::ReversePathMap::iterator it = reversePathMap.find(vd_decl_ka); if(it != reversePathMap.end()) { sl = new StringLit(Location(), it->second); } } else { for(ExpressionSetIter it = e->ann().begin(); it != e->ann().end(); ++it) { if(Call* ca = (*it)->dyn_cast()) { if(ca->id() == constants().ann.mzn_path) { StringLit* sl1 = ca->arg(0)->cast(); if(sl) { if(sl1->v().size() > sl->v().size()) sl = sl1; } else { sl = sl1; } } } } } return sl; } void addPathAnnotation(EnvI& env, Expression* e) { if(!(e->type().isann() || e->isa()) && e->type().dim() == 0) { GCLock lock; Annotation& ann = e->ann(); if(ann.containsCall(constants().ann.mzn_path)) return; EnvI::ReversePathMap& reversePathMap = env.getReversePathMap(); std::vector path_args(1); std::string p; KeepAlive e_ka (e); EnvI::ReversePathMap::iterator it = reversePathMap.find(e_ka); if(it == reversePathMap.end()) { p = getPath(env); } else { p = it->second; } if(p.size() != 0) { path_args[0] = new StringLit(Location(), p); Call* path_call = new Call(e->loc(), constants().ann.mzn_path, path_args); path_call->type(Type::ann()); e->addAnnotation(path_call); } } } VarDecl* newVarDecl(EnvI& env, Ctx ctx, TypeInst* ti, Id* origId, VarDecl* origVd, Expression* rhs) { VarDecl* vd = nullptr; // Is this vardecl already in the FlatZinc (for unification) bool hasBeenAdded = false; // Don't use paths for arrays or annotations if(ti->type().dim() == 0 && !ti->type().isann()) { std::string path = getPath(env); if(!path.empty()) { EnvI::ReversePathMap& reversePathMap = env.getReversePathMap(); EnvI::PathMap& pathMap = env.getPathMap(); EnvI::PathMap::iterator it = pathMap.find(path); if(it != pathMap.end()) { VarDecl* ovd = Expression::cast((it->second.decl)()); unsigned int ovd_pass = it->second.pass_no; if(ovd) { // If ovd was introduced during the same pass, we can unify if(env.current_pass_no == ovd_pass) { vd = ovd; if(origId) origId->decl(vd); hasBeenAdded = true; } else { vd = new VarDecl(getLoc(env, origVd, rhs), ti, getId(env, origId)); hasBeenAdded = false; updateBounds(env, ovd, vd); } // Check whether ovd was unified in a previous pass if(ovd->id() != ovd->id()->decl()->id()) { // We may not have seen the pointed to decl just yet KeepAlive ovd_decl_ka(ovd->id()->decl()); EnvI::ReversePathMap::iterator path2It = reversePathMap.find(ovd_decl_ka); if(path2It != reversePathMap.end()) { std::string path2 = path2It->second; EnvI::PathVar vd_tup {vd, env.current_pass_no}; pathMap[path] = vd_tup; pathMap[path2] = vd_tup; KeepAlive vd_ka(vd); reversePathMap.insert(vd_ka, path); } } } } else { // Create new VarDecl and add it to the maps vd = new VarDecl(getLoc(env, origVd, rhs), ti, getId(env, origId)); hasBeenAdded = false; EnvI::PathVar vd_tup {vd, env.current_pass_no}; pathMap [path] = vd_tup; KeepAlive vd_ka(vd); reversePathMap.insert(vd_ka, path); } } } if(vd == nullptr) { vd = new VarDecl(getLoc(env, origVd, rhs), ti, getId(env, origId)); hasBeenAdded = false; } // If vd has an e() use bind to turn rhs into a constraint if (vd->e()) { if(rhs) { bind(env, ctx, vd, rhs); } } else { vd->e(rhs); if (rhs && hasBeenAdded) { // This variable is being reused, so it won't be added to the model below. // Therefore, we need to register that we changed the RHS, in order // for the reference counts to be accurate. env.vo_add_exp(vd); } } assert(!vd->type().isbot()); if (origVd && (origVd->id()->idn()!=-1 || origVd->toplevel())) { vd->introduced(origVd->introduced()); } else { vd->introduced(true); } vd->flat(vd); // Copy annotations from origVd if (origVd) { for (ExpressionSetIter it = origVd->ann().begin(); it != origVd->ann().end(); ++it) { EE ee_ann = flat_exp(env, Ctx(), *it, NULL, constants().var_true); vd->addAnnotation(ee_ann.r()); } } if (!hasBeenAdded) { if (FunctionI* fi = env.model->matchRevMap(env, vd->type())) { // We need to introduce a reverse mapper Call* revmap = new Call(Location().introduce(), fi->id(), {vd->id()}); revmap->decl(fi); revmap->type(Type::varbool()); env.flat_addItem(new ConstraintI(Location().introduce(), revmap)); } VarDeclI* ni = new VarDeclI(Location().introduce(),vd); env.flat_addItem(ni); EE ee(vd,NULL); env.cse_map_insert(vd->id(),ee); } return vd; } #define MZN_FILL_REIFY_MAP(T,ID) reifyMap.insert(std::pair(constants().ids.T.ID,constants().ids.T ## reif.ID)); EnvI::EnvI(Model* model0, std::ostream& outstream0, std::ostream& errstream0) : model(model0), orig_model(NULL), output(new Model), outstream(outstream0), errstream(errstream0), current_pass_no(0), final_pass_no(1), maxPathDepth(0), ignorePartial(false), ignoreUnknownIds(false), maxCallStack(0), collect_vardecls(false), in_redundant_constraint(0), in_maybe_partial(0), in_reverse_map_var(false), n_reif_ct(0), n_imp_ct(0), n_imp_del(0), n_lin_del(0), pathUse(0), _flat(new Model), _failed(false), ids(0) { MZN_FILL_REIFY_MAP(int_,lin_eq); MZN_FILL_REIFY_MAP(int_,lin_le); MZN_FILL_REIFY_MAP(int_,lin_ne); MZN_FILL_REIFY_MAP(int_,plus); MZN_FILL_REIFY_MAP(int_,minus); MZN_FILL_REIFY_MAP(int_,times); MZN_FILL_REIFY_MAP(int_,div); MZN_FILL_REIFY_MAP(int_,mod); MZN_FILL_REIFY_MAP(int_,lt); MZN_FILL_REIFY_MAP(int_,le); MZN_FILL_REIFY_MAP(int_,gt); MZN_FILL_REIFY_MAP(int_,ge); MZN_FILL_REIFY_MAP(int_,eq); MZN_FILL_REIFY_MAP(int_,ne); MZN_FILL_REIFY_MAP(float_,lin_eq); MZN_FILL_REIFY_MAP(float_,lin_le); MZN_FILL_REIFY_MAP(float_,lin_lt); MZN_FILL_REIFY_MAP(float_,lin_ne); MZN_FILL_REIFY_MAP(float_,plus); MZN_FILL_REIFY_MAP(float_,minus); MZN_FILL_REIFY_MAP(float_,times); MZN_FILL_REIFY_MAP(float_,div); MZN_FILL_REIFY_MAP(float_,mod); MZN_FILL_REIFY_MAP(float_,lt); MZN_FILL_REIFY_MAP(float_,le); MZN_FILL_REIFY_MAP(float_,gt); MZN_FILL_REIFY_MAP(float_,ge); MZN_FILL_REIFY_MAP(float_,eq); MZN_FILL_REIFY_MAP(float_,ne); reifyMap.insert(std::pair(constants().ids.forall,constants().ids.forall_reif)); reifyMap.insert(std::pair(constants().ids.bool_eq,constants().ids.bool_eq_reif)); reifyMap.insert(std::pair(constants().ids.bool_clause,constants().ids.bool_clause_reif)); reifyMap.insert(std::pair(constants().ids.clause,constants().ids.bool_clause_reif)); } EnvI::~EnvI(void) { delete _flat; delete output; delete model; delete orig_model; } long long int EnvI::genId(void) { return ids++; } void EnvI::cse_map_insert(Expression* e, const EE& ee) { KeepAlive ka(e); cse_map.insert(ka,WW(ee.r(),ee.b())); } EnvI::CSEMap::iterator EnvI::cse_map_find(Expression* e) { KeepAlive ka(e); CSEMap::iterator it = cse_map.find(ka); if (it != cse_map.end()) { if (it->second.r()) { VarDecl* it_vd = it->second.r()->isa() ? it->second.r()->cast()->decl() : it->second.r()->dyn_cast(); if (it_vd) { int idx = vo.find(it_vd); if (idx == -1 || (*_flat)[idx]->removed()) return cse_map.end(); } } else { return cse_map.end(); } } return it; } void EnvI::cse_map_remove(Expression* e) { KeepAlive ka(e); cse_map.remove(ka); } EnvI::CSEMap::iterator EnvI::cse_map_end(void) { return cse_map.end(); } void EnvI::dump(void) { struct EED { static std::string k(Expression* e) { std::ostringstream oss; oss << *e; return oss.str(); } static std::string d(const WW& ee) { std::ostringstream oss; oss << *ee.r() << " " << ee.b(); return oss.str(); } }; cse_map.dump(); } void EnvI::flat_addItem(Item* i) { assert(_flat); if (_failed) return; _flat->addItem(i); Expression* toAnnotate = NULL; Expression* toAdd = NULL; switch (i->iid()) { case Item::II_VD: { VarDeclI* vd = i->cast(); addPathAnnotation(*this, vd->e()); toAnnotate = vd->e()->e(); vo.add_idx(vd, _flat->size()-1); toAdd = vd->e(); break; } case Item::II_CON: { ConstraintI* ci = i->cast(); if (ci->e()->isa() && !ci->e()->cast()->v()) { fail(); } else { toAnnotate = ci->e(); addPathAnnotation(*this, ci->e()); toAdd = ci->e(); } break; } case Item::II_SOL: { SolveI* si = i->cast(); CollectOccurrencesE ce(vo,si); topDown(ce,si->e()); for (ExpressionSetIter it = si->ann().begin(); it != si->ann().end(); ++it) topDown(ce,*it); break; } case Item::II_OUT: { OutputI* si = i->cast(); toAdd = si->e(); break; } default: break; } if (toAnnotate && toAnnotate->isa()) { annotateFromCallStack(toAnnotate); } if (toAdd) { CollectOccurrencesE ce(vo,i); topDown(ce,toAdd); } } void EnvI::annotateFromCallStack(Expression* e) { int prev = idStack.size() > 0 ? idStack.back() : 0; bool allCalls = true; for (int i = static_cast(callStack.size())-1; i >= prev; i--) { Expression* ee = callStack[i]->untag(); allCalls = allCalls && (i==callStack.size()-1 || ee->isa()); for (ExpressionSetIter it = ee->ann().begin(); it != ee->ann().end(); ++it) { EE ee_ann = flat_exp(*this, Ctx(), *it, NULL, constants().var_true); if (allCalls || !isDefinesVarAnn(ee_ann.r())) e->addAnnotation(ee_ann.r()); } } } void EnvI::copyPathMapsAndState(EnvI& env) { final_pass_no = env.final_pass_no; maxPathDepth = env.maxPathDepth; current_pass_no = env.current_pass_no; filenameMap = env.filenameMap; maxPathDepth = env.maxPathDepth; pathMap = env.getPathMap(); reversePathMap = env.getReversePathMap(); } void EnvI::flat_removeItem(MiniZinc::Item* i) { i->remove(); } void EnvI::flat_removeItem(int i) { flat_removeItem((*_flat)[i]); } void EnvI::fail(const std::string& msg) { if (!_failed) { addWarning(std::string("model inconsistency detected")+(msg.empty() ? std::string() : (": "+msg))); _failed = true; for (unsigned int i=0; i<_flat->size(); i++) { (*_flat)[i]->remove(); } ConstraintI* failedConstraint = new ConstraintI(Location().introduce(),constants().lit_false); _flat->addItem(failedConstraint); _flat->addItem(SolveI::sat(Location().introduce())); for (unsigned int i=0; isize(); i++) { (*output)[i]->remove(); } output->addItem(new OutputI(Location().introduce(),new ArrayLit(Location(),std::vector()))); throw ModelInconsistent(*this, Location().introduce()); } } bool EnvI::failed() const { return _failed; } unsigned int EnvI::registerEnum(VarDeclI* vdi) { EnumMap::iterator it = enumMap.find(vdi); unsigned int ret; if (it == enumMap.end()) { ret = static_cast(enumVarDecls.size()); enumVarDecls.push_back(vdi); enumMap.insert(std::make_pair(vdi, ret)); } else { ret = it->second; } return ret+1; } VarDeclI* EnvI::getEnum(unsigned int i) const { assert(i > 0 && i <= enumVarDecls.size()); return enumVarDecls[i-1]; } unsigned int EnvI::registerArrayEnum(const std::vector& arrayEnum) { std::ostringstream oss; for (unsigned int i=0; i(arrayEnumDecls.size()); arrayEnumDecls.push_back(arrayEnum); arrayEnumMap.insert(std::make_pair(oss.str(), ret)); } else { ret = it->second; } return ret+1; } const std::vector& EnvI::getArrayEnum(unsigned int i) const { assert(i > 0 && i <= arrayEnumDecls.size()); return arrayEnumDecls[i-1]; } bool EnvI::isSubtype(const Type& t1, const Type& t2, bool strictEnums) { if (!t1.isSubtypeOf(t2,strictEnums)) return false; if (strictEnums && t1.dim()==0 && t2.dim()!=0 && t2.enumId() != 0) { // set assigned to an array const std::vector& t2enumIds = getArrayEnum(t2.enumId()); if (t2enumIds[t2enumIds.size()-1] != 0 && t1.enumId() != t2enumIds[t2enumIds.size()-1]) return false; } if (strictEnums && t1.dim() > 0 && t1.enumId() != t2.enumId()) { if (t1.enumId()==0) { return t1.isbot(); } if (t2.enumId()!=0) { const std::vector& t1enumIds = getArrayEnum(t1.enumId()); const std::vector& t2enumIds = getArrayEnum(t2.enumId()); assert(t1enumIds.size() == t2enumIds.size()); for (unsigned int i=0; ie() && vd->e()->isa() && !vd->e()->type().isann()) { int prev = idStack.size() > 0 ? idStack.back() : 0; for (int i = static_cast(callStack.size())-1; i >= prev; i--) { Expression* ee = callStack[i]->untag(); for (ExpressionSetIter it = ee->ann().begin(); it != ee->ann().end(); ++it) { Expression* ann = *it; if (ann != constants().ann.add_to_output && ann != constants().ann.rhs_from_assignment) { bool needAnnotation = true; if (Call* ann_c = ann->dyn_cast()) { if (ann_c->id()==constants().ann.defines_var) { // only add defines_var annotation if vd is the defined variable if (Id* defined_var = ann_c->arg(0)->dyn_cast()) { if (defined_var->decl() != vd->id()->decl()) { needAnnotation = false; } } } } if (needAnnotation) { EE ee_ann = flat_exp(*this, Ctx(), *it, NULL, constants().var_true); vd->e()->addAnnotation(ee_ann.r()); } } } } } int idx = vo.find(vd); CollectOccurrencesE ce(vo,(*_flat)[idx]); topDown(ce, vd->e()); if (collect_vardecls) modifiedVarDecls.push_back(idx); } Model* EnvI::flat(void) { return _flat; } void EnvI::swap() { Model* tmp = model; model = _flat; _flat = tmp; } ASTString EnvI::reifyId(const ASTString& id) { ASTStringMap::t::iterator it = reifyMap.find(id); if (it == reifyMap.end()) { return id.str()+"_reif"; } else { return it->second; } } #undef MZN_FILL_REIFY_MAP ASTString EnvI::halfReifyId(const ASTString& id) { return id.str() + "_imp"; } void EnvI::addWarning(const std::string& msg) { if (warnings.size()>20) return; if (warnings.size()==20) { warnings.push_back("Further warnings have been suppressed.\n"); } else { std::ostringstream oss; createErrorStack(); dumpStack(oss, true); warnings.push_back(msg+"\n"+oss.str()); } } void EnvI::createErrorStack(void) { errorStack.clear(); for (unsigned int i=static_cast(callStack.size()); i--;) { Expression* e = callStack[i]->untag(); bool isCompIter = callStack[i]->isTagged(); KeepAlive ka(e); errorStack.push_back(std::make_pair(ka,isCompIter)); } } Call* EnvI::surroundingCall(void) const { if (callStack.size() >= 2) return callStack[callStack.size()-2]->untag()->dyn_cast(); return NULL; } void EnvI::cleanupExceptOutput() { cmap.clear(); cse_map.clear(); delete _flat; delete model; delete orig_model; _flat=0; model=0; } CallStackItem::CallStackItem(EnvI& env0, Expression* e) : env(env0) { if (e->isa()) env.idStack.push_back(static_cast(env.callStack.size())); if (e->isa() && e->cast()->id()=="redundant_constraint") env.in_redundant_constraint++; if (e->ann().contains(constants().ann.maybe_partial)) env.in_maybe_partial++; env.callStack.push_back(e); env.maxCallStack = std::max(env.maxCallStack, static_cast(env.callStack.size())); } CallStackItem::CallStackItem(EnvI& env0, Id* ident, IntVal i) : env(env0) { Expression* ee = ident->tag(); env.callStack.push_back(ee); env.maxCallStack = std::max(env.maxCallStack, static_cast(env.callStack.size())); } CallStackItem::~CallStackItem(void) { Expression* e = env.callStack.back()->untag(); if (e->isa()) env.idStack.pop_back(); if (e->isa() && e->cast()->id()=="redundant_constraint") env.in_redundant_constraint--; if (e->ann().contains(constants().ann.maybe_partial)) env.in_maybe_partial--; env.callStack.pop_back(); } FlatteningError::FlatteningError(EnvI& env, const Location& loc, const std::string& msg) : LocationException(env,loc,msg) {} Env::Env(Model* m, std::ostream& outstream, std::ostream& errstream) : e(new EnvI(m,outstream,errstream)) {} Env::~Env(void) { delete e; } Model* Env::model(void) { return e->model; } void Env::model(Model* m) { e->model = m; } Model* Env::flat(void) { return e->flat(); } void Env::swap() { e->swap(); } Model* Env::output(void) { return e->output; } std::ostream& Env::evalOutput(std::ostream& os) { return e->evalOutput(os); } EnvI& Env::envi(void) { return *e; } const EnvI& Env::envi(void) const { return *e; } std::ostream& Env::dumpErrorStack(std::ostream& os) { return e->dumpStack(os, true); } bool EnvI::dumpPath(std::ostream& os, bool force) { force = force ? force : fopts.collect_mzn_paths; if (callStack.size() > maxPathDepth) { if(!force && current_pass_no >= final_pass_no-1) { return false; } maxPathDepth = static_cast(callStack.size()); } unsigned int lastError = static_cast(callStack.size()); std::string major_sep = ";"; std::string minor_sep = "|"; for (unsigned int i=0; iuntag(); bool isCompIter = callStack[i]->isTagged(); Location loc = e->loc(); int filenameId; std::unordered_map::iterator findFilename = filenameMap.find(loc.filename().str()); if (findFilename == filenameMap.end()) { if(!force && current_pass_no >= final_pass_no-1) return false; filenameId = static_cast(filenameMap.size()); filenameMap.insert(std::make_pair(loc.filename().str(), static_cast(filenameMap.size()))); } else { filenameId = findFilename->second; } // If this call is not a dummy StringLit with empty Location (so that deferred compilation doesn't drop the paths) if(e->eid() != Expression::E_STRINGLIT || loc.first_line() || loc.first_column() || loc.last_line() || loc.last_column()) { os << loc.filename().str() << minor_sep << loc.first_line() << minor_sep << loc.first_column() << minor_sep << loc.last_line() << minor_sep << loc.last_column() << minor_sep; switch (e->eid()) { case Expression::E_INTLIT: os << "il" << minor_sep << *e; break; case Expression::E_FLOATLIT: os << "fl" << minor_sep << *e; break; case Expression::E_SETLIT: os << "sl" << minor_sep << *e; break; case Expression::E_BOOLLIT: os << "bl" << minor_sep << *e; break; case Expression::E_STRINGLIT: os << "stl" << minor_sep << *e; break; case Expression::E_ID: if (isCompIter) { //if (e->cast()->decl()->e()->type().ispar()) os << *e << "=" << *e->cast()->decl()->e(); //else // os << *e << "=?"; } else { os << "id" << minor_sep << *e; } break; case Expression::E_ANON: os << "anon"; break; case Expression::E_ARRAYLIT: os << "al"; break; case Expression::E_ARRAYACCESS: os << "aa"; break; case Expression::E_COMP: { const Comprehension* cmp = e->cast(); if (cmp->set()) os << "sc"; else os << "ac"; } break; case Expression::E_ITE: os << "ite"; break; case Expression::E_BINOP: os << "bin" << minor_sep << e->cast()->opToString(); break; case Expression::E_UNOP: os << "un" << minor_sep << e->cast()->opToString(); break; case Expression::E_CALL: if(fopts.only_toplevel_paths) return false; os << "ca" << minor_sep << e->cast()->id(); break; case Expression::E_VARDECL: os << "vd"; break; case Expression::E_LET: os << "l"; break; case Expression::E_TI: os << "ti"; break; case Expression::E_TIID: os << "ty"; break; default: assert(false); os << "unknown expression (internal error)"; break; } os << major_sep; } else { os << e->cast()->v() << major_sep; } } return true; } std::ostream& EnvI::dumpStack(std::ostream& os, bool errStack) { int lastError = 0; std::vector errStackCopy; if (errStack) { errStackCopy.resize(errorStack.size()); for (unsigned int i=0; itag(); } errStackCopy[i] = e; } } std::vector& stack = errStack ? errStackCopy : callStack; for (; lastError < stack.size(); lastError++) { Expression* e = stack[lastError]->untag(); bool isCompIter = stack[lastError]->isTagged(); if (e->loc().is_introduced()) continue; if (!isCompIter && e->isa()) { break; } } ASTString curloc_f; int curloc_l = -1; for (int i=lastError-1; i>=0; i--) { Expression* e = stack[i]->untag(); bool isCompIter = stack[i]->isTagged(); ASTString newloc_f = e->loc().filename(); if (e->loc().is_introduced()) continue; int newloc_l = e->loc().first_line(); if (newloc_f != curloc_f || newloc_l != curloc_l) { os << " " << newloc_f << ":" << newloc_l << ":" << std::endl; curloc_f = newloc_f; curloc_l = newloc_l; } if (isCompIter) os << " with "; else os << " in "; switch (e->eid()) { case Expression::E_INTLIT: os << "integer literal" << std::endl; break; case Expression::E_FLOATLIT: os << "float literal" << std::endl; break; case Expression::E_SETLIT: os << "set literal" << std::endl; break; case Expression::E_BOOLLIT: os << "bool literal" << std::endl; break; case Expression::E_STRINGLIT: os << "string literal" << std::endl; break; case Expression::E_ID: if (isCompIter) { if (e->cast()->decl()->e()->type().ispar()) os << *e << " = " << *e->cast()->decl()->e() << std::endl; else os << *e << " = " << std::endl; } else { os << "identifier" << *e << std::endl; } break; case Expression::E_ANON: os << "anonymous variable" << std::endl; break; case Expression::E_ARRAYLIT: os << "array literal" << std::endl; break; case Expression::E_ARRAYACCESS: os << "array access" << std::endl; break; case Expression::E_COMP: { const Comprehension* cmp = e->cast(); if (cmp->set()) os << "set "; else os << "array "; os << "comprehension expression" << std::endl; } break; case Expression::E_ITE: os << "if-then-else expression" << std::endl; break; case Expression::E_BINOP: os << "binary " << e->cast()->opToString() << " operator expression" << std::endl; break; case Expression::E_UNOP: os << "unary " << e->cast()->opToString() << " operator expression" << std::endl; break; case Expression::E_CALL: os << "call '" << e->cast()->id() << "'" << std::endl; break; case Expression::E_VARDECL: { GCLock lock; os << "variable declaration for '" << e->cast()->id()->str() << "'" << std::endl; } break; case Expression::E_LET: os << "let expression" << std::endl; break; case Expression::E_TI: os << "type-inst expression" << std::endl; break; case Expression::E_TIID: os << "type identifier" << std::endl; break; default: assert(false); os << "unknown expression (internal error)" << std::endl; break; } } return os; } void populateOutput(Env& env) { EnvI& envi = env.envi(); Model* _flat = envi.flat(); Model* _output = envi.output; std::vector outputVars; for (VarDeclIterator it = _flat->begin_vardecls(); it != _flat->end_vardecls(); ++it) { VarDecl* vd = it->e(); Annotation& ann = vd->ann(); ArrayLit* dims = NULL; bool has_output_ann = false; if(!ann.isEmpty()) { for(ExpressionSetIter ait = ann.begin(); ait != ann.end(); ++ait) { if (Call* c = (*ait)->dyn_cast()) { if (c->id() == constants().ann.output_array) { dims = c->arg(0)->cast(); has_output_ann = true; break; } } else if ((*ait)->isa() && (*ait)->cast()->str() == constants().ann.output_var->str()) { has_output_ann = true; } } if(has_output_ann) { std::ostringstream s; s << vd->id()->str().str() << " = "; VarDecl* vd_output = copy(env.envi(), vd)->cast(); Type vd_t = vd_output->type(); vd_t.ti(Type::TI_PAR); vd_output->type(vd_t); vd_output->ti()->type(vd_t); _output->addItem(new VarDeclI(Location().introduce(), vd_output)); if (dims) { s << "array" << dims->size() << "d("; for (unsigned int i=0; isize(); i++) { IntSetVal* idxset = eval_intset(envi,(*dims)[i]); s << *idxset << ","; } } StringLit* sl = new StringLit(Location().introduce(),s.str()); outputVars.push_back(sl); std::vector showArgs(1); showArgs[0] = vd_output->id(); Call* show = new Call(Location().introduce(),constants().ids.show,showArgs); show->type(Type::parstring()); FunctionI* fi = _flat->matchFn(envi, show, false); assert(fi); show->decl(fi); outputVars.push_back(show); std::string ends = dims ? ")" : ""; ends += ";\n"; StringLit* eol = new StringLit(Location().introduce(),ends); outputVars.push_back(eol); } } } OutputI* newOutputItem = new OutputI(Location().introduce(),new ArrayLit(Location().introduce(),outputVars)); _output->addItem(newOutputItem); envi.flat()->mergeStdLib(envi, _output); } std::ostream& EnvI::evalOutput(std::ostream &os) { GCLock lock; ArrayLit* al = eval_array_lit(*this,output->outputItem()->e()); bool fLastEOL = true; for (unsigned int i=0; isize(); i++) { std::string s = eval_string(*this, (*al)[i]); if (!s.empty()) { os << s; fLastEOL = ( '\n'==s.back() ); } } if ( !fLastEOL ) os << '\n'; return os; } const std::vector& Env::warnings(void) { return envi().warnings; } void Env::clearWarnings(void) { envi().warnings.clear(); } unsigned int Env::maxCallStack(void) const { return envi().maxCallStack; } void checkIndexSets(EnvI& env, VarDecl* vd, Expression* e) { ASTExprVec tis = vd->ti()->ranges(); std::vector newtis(tis.size()); bool needNewTypeInst = false; GCLock lock; switch (e->eid()) { case Expression::E_ID: { Id* id = e->cast(); ASTExprVec e_tis = id->decl()->ti()->ranges(); assert(tis.size()==e_tis.size()); for (unsigned int i=0; idomain()==NULL) { newtis[i] = e_tis[i]; needNewTypeInst = true; } else { if (!eval_intset(env,tis[i]->domain())->equal(eval_intset(env,e_tis[i]->domain()))) throw EvalError(env, vd->loc(), "Index set mismatch"); newtis[i] = tis[i]; } } } break; case Expression::E_ARRAYLIT: { ArrayLit* al = e->cast(); for (unsigned int i=0; idomain()==NULL) { newtis[i] = new TypeInst(Location().introduce(),Type(),new SetLit(Location().introduce(),IntSetVal::a(al->min(i),al->max(i)))); needNewTypeInst = true; } else if (i==0 || al->size() != 0) { IntSetVal* isv = eval_intset(env,tis[i]->domain()); assert(isv->size()<=1); if ( (isv->size()==0 && al->min(i) <= al->max(i)) || (isv->size()!=0 && (isv->min(0) != al->min(i) || isv->max(0) != al->max(i))) ) throw EvalError(env, vd->loc(), "Index set mismatch"); newtis[i] = tis[i]; } } } break; default: throw InternalError("not supported yet"); } if (needNewTypeInst) { TypeInst* tic = copy(env,vd->ti())->cast(); tic->setRanges(newtis); vd->ti(tic); } } /// Turn \a c into domain constraints if possible. /// Return whether \a c is still required in the model. bool checkDomainConstraints(EnvI& env, Call* c) { if (env.fopts.record_domain_changes) return true; if (c->id()==constants().ids.int_.le) { Expression* e0 = c->arg(0); Expression* e1 = c->arg(1); if (e0->type().ispar() && e1->isa()) { // greater than Id* id = e1->cast(); IntVal lb = eval_int(env,e0); if (id->decl()->ti()->domain()) { IntSetVal* domain = eval_intset(env,id->decl()->ti()->domain()); if (domain->min() >= lb) return false; if (domain->max() < lb) { env.fail(); return false; } IntSetRanges dr(domain); Ranges::Const cr(lb,IntVal::infinity()); Ranges::Inter > i(dr,cr); IntSetVal* newibv = IntSetVal::ai(i); id->decl()->ti()->domain(new SetLit(Location().introduce(), newibv)); id->decl()->ti()->setComputedDomain(false); } else { id->decl()->ti()->domain(new SetLit(Location().introduce(), IntSetVal::a(lb,IntVal::infinity()))); } return false; } else if (e1->type().ispar() && e0->isa()) { // less than Id* id = e0->cast(); IntVal ub = eval_int(env,e1); if (id->decl()->ti()->domain()) { IntSetVal* domain = eval_intset(env,id->decl()->ti()->domain()); if (domain->max() <= ub) return false; if (domain->min() > ub) { env.fail(); return false; } IntSetRanges dr(domain); Ranges::Const cr(-IntVal::infinity(), ub); Ranges::Inter > i(dr,cr); IntSetVal* newibv = IntSetVal::ai(i); id->decl()->ti()->domain(new SetLit(Location().introduce(), newibv)); id->decl()->ti()->setComputedDomain(false); } else { id->decl()->ti()->domain(new SetLit(Location().introduce(), IntSetVal::a(-IntVal::infinity(), ub))); } } } else if (c->id()==constants().ids.int_.lin_le) { ArrayLit* al_c = follow_id(c->arg(0))->cast(); if (al_c->size()==1) { ArrayLit* al_x = follow_id(c->arg(1))->cast(); IntVal coeff = eval_int(env,(*al_c)[0]); IntVal y = eval_int(env,c->arg(2)); IntVal lb = -IntVal::infinity(); IntVal ub = IntVal::infinity(); IntVal r = y % coeff; if (coeff >= 0) { ub = y / coeff; if (r<0) --ub; } else { lb = y / coeff; if (r<0) ++lb; } if (Id* id = (*al_x)[0]->dyn_cast()) { if (id->decl()->ti()->domain()) { IntSetVal* domain = eval_intset(env,id->decl()->ti()->domain()); if (domain->max() <= ub && domain->min() >= lb) return false; if (domain->min() > ub || domain->max() < lb) { env.fail(); return false; } IntSetRanges dr(domain); Ranges::Const cr(lb, ub); Ranges::Inter > i(dr,cr); IntSetVal* newibv = IntSetVal::ai(i); id->decl()->ti()->domain(new SetLit(Location().introduce(), newibv)); id->decl()->ti()->setComputedDomain(false); } else { id->decl()->ti()->domain(new SetLit(Location().introduce(), IntSetVal::a(lb, ub))); } return false; } } } return true; } KeepAlive bind(EnvI& env, Ctx ctx, VarDecl* vd, Expression* e) { assert(e==NULL || !e->isa()); if (vd==constants().var_ignore) return e; if (Id* ident = e->dyn_cast()) { if (ident->decl()) { VarDecl* e_vd = follow_id_to_decl(ident)->cast(); e = e_vd->id(); if (!env.in_reverse_map_var && ctx.b != C_ROOT && e->type()==Type::varbool()) { addCtxAnn(e_vd, ctx.b); if (e_vd != ident->decl()) { addCtxAnn(ident->decl(), ctx.b); } } } } if (ctx.neg) { assert(e->type().bt() == Type::BT_BOOL); if (vd==constants().var_true) { if (!isfalse(env,e)) { if (Id* id = e->dyn_cast()) { while (id != NULL) { assert(id->decl() != NULL); if (id->decl()->ti()->domain() && istrue(env,id->decl()->ti()->domain())) { GCLock lock; env.flat_addItem(new ConstraintI(Location().introduce(),constants().lit_false)); } else { id->decl()->ti()->domain(constants().lit_false); GCLock lock; std::vector args(2); args[0] = id; args[1] = constants().lit_false; Call* c = new Call(Location().introduce(),constants().ids.bool_eq,args); c->decl(env.model->matchFn(env,c,false)); c->type(c->decl()->rtype(env,args,false)); if (c->decl()->e()) { flat_exp(env, Ctx(), c, constants().var_true, constants().var_true); } } id = id->decl()->e() ? id->decl()->e()->dyn_cast() : NULL; } return constants().lit_true; } else { GC::lock(); BinOp* bo = new BinOp(e->loc(),e,BOT_EQUIV,constants().lit_false); bo->type(e->type()); KeepAlive ka(bo); GC::unlock(); EE ee = flat_exp(env,Ctx(),bo,NULL,constants().var_true); return bind(env,Ctx(),vd,ee.r()); } } return constants().lit_true; } else { GC::lock(); BinOp* bo = new BinOp(e->loc(),e,BOT_EQUIV,constants().lit_false); bo->type(e->type()); KeepAlive ka(bo); GC::unlock(); EE ee = flat_exp(env,Ctx(),bo,NULL,constants().var_true); return bind(env,Ctx(),vd,ee.r()); } } else { if (vd==constants().var_true) { if (!istrue(env,e)) { if (Id* id = e->dyn_cast()) { assert(id->decl() != NULL); while (id != NULL) { if (id->decl()->ti()->domain() && isfalse(env,id->decl()->ti()->domain())) { GCLock lock; env.flat_addItem(new ConstraintI(Location().introduce(),constants().lit_false)); } else if (id->decl()->ti()->domain()==NULL) { id->decl()->ti()->domain(constants().lit_true); GCLock lock; std::vector args(2); args[0] = id; args[1] = constants().lit_true; Call* c = new Call(Location().introduce(),constants().ids.bool_eq,args); c->decl(env.model->matchFn(env,c,false)); c->type(c->decl()->rtype(env,args,false)); if (c->decl()->e()) { flat_exp(env, Ctx(), c, constants().var_true, constants().var_true); } } id = id->decl()->e() ? id->decl()->e()->dyn_cast() : NULL; } } else { GCLock lock; // extract domain information from added constraint if possible if (!e->isa() || checkDomainConstraints(env,e->cast())) { env.flat_addItem(new ConstraintI(Location().introduce(),e)); } } } return constants().lit_true; } else if (vd==constants().var_false) { if (!isfalse(env,e)) { throw InternalError("not supported yet"); } return constants().lit_true; } else if (vd==NULL) { if (e==NULL) return NULL; switch (e->eid()) { case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_BOOLLIT: case Expression::E_STRINGLIT: case Expression::E_ANON: case Expression::E_ID: case Expression::E_TIID: case Expression::E_SETLIT: case Expression::E_VARDECL: return e; case Expression::E_BINOP: case Expression::E_UNOP: return e; /// TODO: should not happen once operators are evaluated case Expression::E_ARRAYACCESS: case Expression::E_COMP: case Expression::E_ITE: case Expression::E_LET: case Expression::E_TI: throw InternalError("unevaluated expression"); case Expression::E_ARRAYLIT: { GCLock lock; ArrayLit* al = e->cast(); /// TODO: review if limit of 10 is a sensible choice if (al->type().bt()==Type::BT_ANN || al->size() <= 10) return e; EnvI::CSEMap::iterator it = env.cse_map_find(al); if (it != env.cse_map_end()) { return it->second.r()->cast()->id(); } std::vector ranges(al->dims()); for (unsigned int i=0; iloc(), Type(), new SetLit(Location().introduce(),IntSetVal::a(al->min(i),al->max(i)))); } ASTExprVec ranges_v(ranges); assert(!al->type().isbot()); Expression* domain = NULL; if (al->size() > 0 && (*al)[0]->type().isint()) { IntVal min = IntVal::infinity(); IntVal max = -IntVal::infinity(); for (unsigned int i=0; isize(); i++) { IntBounds ib = compute_int_bounds(env,(*al)[i]); if (!ib.valid) { min = -IntVal::infinity(); max = IntVal::infinity(); break; } min = std::min(min, ib.l); max = std::max(max, ib.u); } if (min != -IntVal::infinity() && max != IntVal::infinity()) { domain = new SetLit(Location().introduce(), IntSetVal::a(min,max)); } } TypeInst* ti = new TypeInst(e->loc(),al->type(),ranges_v,domain); if (domain) ti->setComputedDomain(true); VarDecl* vd = newVarDecl(env, ctx, ti, NULL, NULL, al); EE ee(vd,NULL); env.cse_map_insert(al,ee); env.cse_map_insert(vd->e(),ee); return vd->id(); } case Expression::E_CALL: { if (e->type().isann()) return e; GCLock lock; /// TODO: handle array types TypeInst* ti = new TypeInst(Location().introduce(),e->type()); VarDecl* vd = newVarDecl(env, ctx, ti, NULL, NULL, e); if (vd->e()->type().bt()==Type::BT_INT && vd->e()->type().dim()==0) { IntSetVal* ibv = NULL; if (vd->e()->type().is_set()) { ibv = compute_intset_bounds(env,vd->e()); } else { IntBounds ib = compute_int_bounds(env,vd->e()); if (ib.valid) { ibv = IntSetVal::a(ib.l,ib.u); } } if (ibv) { Id* id = vd->id(); while (id != NULL) { if (id->decl()->ti()->domain()) { IntSetVal* domain = eval_intset(env,id->decl()->ti()->domain()); IntSetRanges dr(domain); IntSetRanges ibr(ibv); Ranges::Inter i(dr,ibr); IntSetVal* newibv = IntSetVal::ai(i); if (ibv->card() == newibv->card()) { id->decl()->ti()->setComputedDomain(true); } else { ibv = newibv; } } else { id->decl()->ti()->setComputedDomain(true); } if (id->type().st()==Type::ST_PLAIN && ibv->size()==0) { env.fail(); } else { id->decl()->ti()->domain(new SetLit(Location().introduce(),ibv)); } id = id->decl()->e() ? id->decl()->e()->dyn_cast() : NULL; } } } else if (vd->e()->type().isbool()) { addCtxAnn(vd, ctx.b); } else if (vd->e()->type().bt()==Type::BT_FLOAT && vd->e()->type().dim()==0) { FloatBounds fb = compute_float_bounds(env,vd->e()); FloatSetVal* ibv = LinearTraits::intersect_domain(NULL, fb.l, fb.u); if (fb.valid) { Id* id = vd->id(); while (id != NULL) { if (id->decl()->ti()->domain()) { FloatSetVal* domain = eval_floatset(env,id->decl()->ti()->domain()); FloatSetVal* ndomain = LinearTraits::intersect_domain(domain, fb.l, fb.u); if (ibv && ndomain==domain) { id->decl()->ti()->setComputedDomain(true); } else { ibv = ndomain; } } else { id->decl()->ti()->setComputedDomain(true); } if (LinearTraits::domain_empty(ibv)) { env.fail(); } else { id->decl()->ti()->domain(new SetLit(Location(), ibv)); } id = id->decl()->e() ? id->decl()->e()->dyn_cast() : NULL; } } } return vd->id(); } default: assert(false); return NULL; } } else { if (vd->e()==NULL) { Expression* ret = e; if (e==NULL || (e->type().ispar() && e->type().isbool())) { GCLock lock; bool isTrue = (e==NULL || eval_bool(env,e)); // Check if redefinition of bool_eq exists, if yes call it std::vector args(2); args[0] = vd->id(); args[1] = constants().boollit(isTrue); Call* c = new Call(Location().introduce(),constants().ids.bool_eq,args); c->decl(env.model->matchFn(env,c,false)); c->type(c->decl()->rtype(env,args,false)); bool didRewrite = false; if (c->decl()->e()) { flat_exp(env, Ctx(), c, constants().var_true, constants().var_true); didRewrite = true; } vd->e(constants().boollit(isTrue)); if (vd->ti()->domain()) { if (vd->ti()->domain() != vd->e()) { env.fail(); return vd->id(); } } else { vd->ti()->domain(vd->e()); vd->ti()->setComputedDomain(true); } if (didRewrite) { return vd->id(); } } else { if (e->type().dim() > 0) { // Check that index sets match env.errorStack.clear(); checkIndexSets(env,vd,e); ArrayLit* al = Expression::dyn_cast(e->isa() ? e->cast()->decl()->e() : e); if (al && vd->ti()->domain() && !vd->ti()->domain()->isa()) { if (e->type().bt()==Type::BT_INT) { IntSetVal* isv = eval_intset(env, vd->ti()->domain()); for (unsigned int i=0; isize(); i++) { if (Id* id = (*al)[i]->dyn_cast()) { VarDecl* vdi = id->decl(); if (vdi->ti()->domain()==NULL) { vdi->ti()->domain(vd->ti()->domain()); } else { IntSetVal* vdi_dom = eval_intset(env, vdi->ti()->domain()); IntSetRanges isvr(isv); IntSetRanges vdi_domr(vdi_dom); Ranges::Inter inter(isvr,vdi_domr); IntSetVal* newdom = IntSetVal::ai(inter); if (newdom->size()==0) { env.fail(); } else { IntSetRanges vdi_domr2(vdi_dom); IntSetRanges newdomr(newdom); if (!Ranges::equal(vdi_domr2, newdomr)) { vdi->ti()->domain(new SetLit(Location().introduce(),newdom)); vdi->ti()->setComputedDomain(false); } } } } else { // at this point, can only be a constant assert((*al)[i]->type().ispar()); if (e->type().st()==Type::ST_PLAIN) { IntVal iv = eval_int(env, (*al)[i]); if (!isv->contains(iv)) { std::ostringstream oss; oss << "value " << iv << " outside declared array domain " << *isv; env.fail(oss.str()); } } else { IntSetVal* aisv = eval_intset(env, (*al)[i]); IntSetRanges aisv_r(aisv); IntSetRanges isv_r(isv); if (!Ranges::subset(aisv_r,isv_r)) { std::ostringstream oss; oss << "value " << *aisv << " outside declared array domain " << *isv; env.fail(oss.str()); } } } } vd->ti()->setComputedDomain(true); } else if (e->type().bt()==Type::BT_FLOAT) { FloatSetVal* fsv = eval_floatset(env, vd->ti()->domain()); for (unsigned int i=0; isize(); i++) { if (Id* id = (*al)[i]->dyn_cast()) { VarDecl* vdi = id->decl(); if (vdi->ti()->domain()==NULL) { vdi->ti()->domain(vd->ti()->domain()); } else { FloatSetVal* vdi_dom = eval_floatset(env, vdi->ti()->domain()); FloatSetRanges fsvr(fsv); FloatSetRanges vdi_domr(vdi_dom); Ranges::Inter inter(fsvr,vdi_domr); FloatSetVal* newdom = FloatSetVal::ai(inter); if (newdom->size()==0) { env.fail(); } else { FloatSetRanges vdi_domr2(vdi_dom); FloatSetRanges newdomr(newdom); if (!Ranges::equal(vdi_domr2, newdomr)) { vdi->ti()->domain(new SetLit(Location().introduce(),newdom)); vdi->ti()->setComputedDomain(false); } } } } else { // at this point, can only be a constant assert((*al)[i]->type().ispar()); FloatVal fv = eval_float(env, (*al)[i]); if (!fsv->contains(fv)) { std::ostringstream oss; oss << "value " << fv << " outside declared array domain " << *fsv; env.fail(oss.str()); } } } vd->ti()->setComputedDomain(true); } } } else if (Id* e_id = e->dyn_cast()) { if (e_id == vd->id()) { ret = vd->id(); } else { ASTString cid; if (e->type().isint()) { if (e->type().isopt()) { cid = ASTString("int_opt_eq"); } else { cid = constants().ids.int_.eq; } } else if (e->type().isbool()) { if (e->type().isopt()) { cid = ASTString("bool_opt_eq"); } else { cid = constants().ids.bool_eq; } } else if (e->type().is_set()) { cid = constants().ids.set_eq; } else if (e->type().isfloat()) { cid = constants().ids.float_.eq; } if (cid != "") { GCLock lock; std::vector args(2); args[0] = vd->id(); args[1] = e_id; Call* c = new Call(Location().introduce(),cid,args); c->decl(env.model->matchFn(env,c,false)); c->type(c->decl()->rtype(env,args,false)); if (c->type().isbool() && ctx.b != C_ROOT) { addCtxAnn(vd, ctx.b); addCtxAnn(e_id->decl(), ctx.b); } if (c->decl()->e()) { flat_exp(env, Ctx(), c, constants().var_true, constants().var_true); ret = vd->id(); vd->e(e); env.vo_add_exp(vd); } } } } if (ret != vd->id()) { vd->e(ret); addPathAnnotation(env, ret); env.vo_add_exp(vd); ret = vd->id(); } Id* vde_id = Expression::dyn_cast(vd->e()); if (vde_id && vde_id->decl()->ti()->domain()==NULL) { if (vd->ti()->domain()) { GCLock lock; Expression* vd_dom = eval_par(env, vd->ti()->domain()); vde_id->decl()->ti()->domain(vd_dom); } } else if (vd->e() && vd->e()->type().bt()==Type::BT_INT && vd->e()->type().dim()==0) { GCLock lock; IntSetVal* ibv = NULL; if (vd->e()->type().is_set()) { ibv = compute_intset_bounds(env,vd->e()); } else { IntBounds ib = compute_int_bounds(env,vd->e()); if (ib.valid) { Call* call = vd->e()->dyn_cast(); if (call && call->id()==constants().ids.lin_exp) { ArrayLit* al = eval_array_lit(env, call->arg(1)); if (al->size()==1) { IntBounds check_zeroone = compute_int_bounds(env, (*al)[0]); if (check_zeroone.l==0 && check_zeroone.u==1) { ArrayLit* coeffs = eval_array_lit(env, call->arg(0)); std::vector newdom(2); newdom[0] = 0; newdom[1] = eval_int(env, (*coeffs)[0])+eval_int(env, call->arg(2)); ibv = IntSetVal::a(newdom); } } } if (ibv==NULL) { ibv = IntSetVal::a(ib.l,ib.u); } } } if (ibv) { if (vd->ti()->domain()) { IntSetVal* domain = eval_intset(env,vd->ti()->domain()); IntSetRanges dr(domain); IntSetRanges ibr(ibv); Ranges::Inter i(dr,ibr); IntSetVal* newibv = IntSetVal::ai(i); if (ibv->card() == newibv->card()) { vd->ti()->setComputedDomain(true); } else { ibv = newibv; } } else { vd->ti()->setComputedDomain(true); } SetLit* ibv_l = nullptr; if (Id* rhs_ident = vd->e()->dyn_cast()) { if (rhs_ident->decl()->ti()->domain()) { IntSetVal* rhs_domain = eval_intset(env,rhs_ident->decl()->ti()->domain()); IntSetRanges dr(rhs_domain); IntSetRanges ibr(ibv); Ranges::Inter i(dr,ibr); IntSetVal* rhs_newibv = IntSetVal::ai(i); if (rhs_domain->card() != rhs_newibv->card()) { ibv_l = new SetLit(Location().introduce(),rhs_newibv); rhs_ident->decl()->ti()->domain(ibv_l); rhs_ident->decl()->ti()->setComputedDomain(false); if (rhs_ident->decl()->type().isopt()) { std::vector args(2); args[0] = rhs_ident; args[1] = ibv_l; Call* c = new Call(Location().introduce(), "var_dom", args); c->type(Type::varbool()); c->decl(env.model->matchFn(env, c, false)); (void) flat_exp(env, Ctx(), c, constants().var_true, constants().var_true); } } else if (ibv->card() != rhs_newibv->card()) { ibv_l = new SetLit(Location().introduce(),rhs_newibv); } } } if (ibv_l==nullptr) { ibv_l = new SetLit(Location().introduce(),ibv); } vd->ti()->domain(ibv_l); if (vd->type().isopt()) { std::vector args(2); args[0] = vd->id(); args[1] = ibv_l; Call* c = new Call(Location().introduce(), "var_dom", args); c->type(Type::varbool()); c->decl(env.model->matchFn(env, c, false)); (void) flat_exp(env, Ctx(), c, constants().var_true, constants().var_true); } } } else if (vd->e() && vd->e()->type().bt()==Type::BT_FLOAT && vd->e()->type().dim()==0) { GCLock lock; FloatSetVal* fbv = NULL; FloatBounds fb = compute_float_bounds(env,vd->e()); if (fb.valid) { fbv = FloatSetVal::a(fb.l,fb.u); } if (fbv) { if (vd->ti()->domain()) { FloatSetVal* domain = eval_floatset(env,vd->ti()->domain()); FloatSetRanges dr(domain); FloatSetRanges fbr(fbv); Ranges::Inter i(dr,fbr); FloatSetVal* newfbv = FloatSetVal::ai(i); FloatSetRanges dr_eq(domain); FloatSetRanges newfbv_eq(newfbv); if (Ranges::equal(dr_eq, newfbv_eq)) { vd->ti()->setComputedDomain(true); } else { fbv = newfbv; } } else { vd->ti()->setComputedDomain(true); } SetLit* fbv_l = nullptr; if (Id* rhs_ident = vd->e()->dyn_cast()) { if (rhs_ident->decl()->ti()->domain()) { FloatSetVal* rhs_domain = eval_floatset(env,rhs_ident->decl()->ti()->domain()); FloatSetRanges dr(rhs_domain); FloatSetRanges ibr(fbv); Ranges::Inter i(dr,ibr); FloatSetVal* rhs_newfbv = FloatSetVal::ai(i); if (rhs_domain->card() != rhs_newfbv->card()) { fbv_l = new SetLit(Location().introduce(), rhs_newfbv); rhs_ident->decl()->ti()->domain(fbv_l); rhs_ident->decl()->ti()->setComputedDomain(false); if (rhs_ident->decl()->type().isopt()) { std::vector args(2); args[0] = rhs_ident; args[1] = fbv_l; Call* c = new Call(Location().introduce(), "var_dom", args); c->type(Type::varbool()); c->decl(env.model->matchFn(env, c, false)); (void) flat_exp(env, Ctx(), c, constants().var_true, constants().var_true); } } else if (fbv->card() != rhs_newfbv->card()) { fbv_l = new SetLit(Location().introduce(), rhs_newfbv); } } } fbv_l = new SetLit(Location().introduce(),fbv); vd->ti()->domain(fbv_l); if (vd->type().isopt()) { std::vector args(2); args[0] = vd->id(); args[1] = fbv_l; Call* c = new Call(Location().introduce(), "var_dom", args); c->type(Type::varbool()); c->decl(env.model->matchFn(env, c, false)); (void) flat_exp(env, Ctx(), c, constants().var_true, constants().var_true); } } } } return ret; } else if (vd == e) { return vd->id(); } else if (vd->e() != e) { e = follow_id_to_decl(e); if (vd == e) return vd->id(); switch (e->eid()) { case Expression::E_BOOLLIT: { Id* id = vd->id(); while (id != NULL) { if (id->decl()->ti()->domain() && eval_bool(env,id->decl()->ti()->domain()) == e->cast()->v()) { return constants().lit_true; } else if (id->decl()->ti()->domain() && eval_bool(env,id->decl()->ti()->domain()) != e->cast()->v()) { GCLock lock; env.flat_addItem(new ConstraintI(Location().introduce(),constants().lit_false)); } else { id->decl()->ti()->domain(e); GCLock lock; std::vector args(2); args[0] = id; args[1] = e; Call* c = new Call(Location().introduce(),constants().ids.bool_eq,args); c->decl(env.model->matchFn(env,c,false)); c->type(c->decl()->rtype(env,args,false)); if (c->decl()->e()) { flat_exp(env, Ctx(), c, constants().var_true, constants().var_true); } } id = id->decl()->e() ? id->decl()->e()->dyn_cast() : NULL; } return constants().lit_true; } case Expression::E_VARDECL: { VarDecl* e_vd = e->cast(); if (vd->e()==e_vd->id() || e_vd->e()==vd->id()) return vd->id(); if (e->type().dim() != 0) throw InternalError("not supported yet"); GCLock lock; ASTString cid; if (e->type().isint()) { cid = constants().ids.int_.eq; } else if (e->type().isbool()) { cid = constants().ids.bool_eq; } else if (e->type().is_set()) { cid = constants().ids.set_eq; } else if (e->type().isfloat()) { cid = constants().ids.float_.eq; } else { throw InternalError("not yet implemented"); } std::vector args(2); args[0] = vd->id(); args[1] = e_vd->id(); Call* c = new Call(vd->loc().introduce(),cid,args); c->decl(env.model->matchFn(env,c,false)); c->type(c->decl()->rtype(env,args,false)); flat_exp(env, Ctx(), c, constants().var_true, constants().var_true); return vd->id(); } case Expression::E_CALL: { Call* c = e->cast(); GCLock lock; Call* nc; std::vector args; if (c->id() == constants().ids.lin_exp) { ArrayLit* le_c = follow_id(c->arg(0))->cast(); std::vector ncoeff(le_c->size()); for (unsigned int i=static_cast(ncoeff.size()); i--;) ncoeff[i] = (*le_c)[i]; ncoeff.push_back(IntLit::a(-1)); args.push_back(new ArrayLit(Location().introduce(),ncoeff)); args[0]->type(le_c->type()); ArrayLit* le_x = follow_id(c->arg(1))->cast(); std::vector nx(le_x->size()); for (unsigned int i=static_cast(nx.size()); i--;) nx[i] = (*le_x)[i]; nx.push_back(vd->id()); args.push_back(new ArrayLit(Location().introduce(),nx)); args[1]->type(le_x->type()); args.push_back(c->arg(2)); nc = new Call(c->loc().introduce(), constants().ids.lin_exp, args); nc->decl(env.model->matchFn(env,nc,false)); if (nc->decl() == NULL) { throw InternalError("undeclared function or predicate " +nc->id().str()); } nc->type(nc->decl()->rtype(env,args,false)); BinOp* bop = new BinOp(nc->loc(), nc, BOT_EQ, IntLit::a(0)); bop->type(Type::varbool()); flat_exp(env, Ctx(), bop, constants().var_true, constants().var_true); return vd->id(); } else { args.resize(c->n_args()); for (unsigned int i=static_cast(args.size()); i--;) args[i] = c->arg(i); args.push_back(vd->id()); ASTString nid = c->id(); if (c->id() == constants().ids.exists) { nid = constants().ids.array_bool_or; } else if (c->id() == constants().ids.forall) { nid = constants().ids.array_bool_and; } else if (vd->type().isbool()) { if (env.fopts.enable_imp && vd->ann().contains(constants().ctx.pos)) { nid = env.halfReifyId(c->id()); if (env.model->matchFn(env, nid, args, false) == NULL) { nid = env.reifyId(c->id()); } } else { nid = env.reifyId(c->id()); } } nc = new Call(c->loc().introduce(), nid, args); } FunctionI* nc_decl = env.model->matchFn(env,nc,false); if (nc_decl == NULL) { throw InternalError("undeclared function or predicate " +nc->id().str()); } nc->decl(nc_decl); nc->type(nc->decl()->rtype(env,args,false)); makeDefinedVar(vd, nc); flat_exp(env, Ctx(), nc, constants().var_true, constants().var_true); return vd->id(); } break; default: throw InternalError("not supported yet"); } } else { return e; } } } } KeepAlive conj(EnvI& env,VarDecl* b,Ctx ctx,const std::vector& e) { if (!ctx.neg) { std::vector nontrue; for (unsigned int i=0; i args; ArrayLit* al = new ArrayLit(Location().introduce(),nontrue); al->type(Type::varbool(1)); args.push_back(al); Call* ret = new Call(nontrue[0]->loc().introduce(),constants().ids.forall,args); ret->decl(env.model->matchFn(env,ret,false)); ret->type(ret->decl()->rtype(env,args,false)); KeepAlive ka(ret); GC::unlock(); return flat_exp(env,ctx,ret,b,constants().var_true).r; } } } else { Ctx nctx = ctx; nctx.neg = false; // negated std::vector nonfalse; for (unsigned int i=0; iloc(),UOT_NOT,nonfalse[0]); uo->type(Type::varbool()); KeepAlive ka(uo); GC::unlock(); return flat_exp(env,nctx,uo,b,constants().var_true).r; } else { if (b==constants().var_false) { for (unsigned int i=0; i args; for (unsigned int i=0; iloc(),UOT_NOT,nonfalse[i]); uo->type(Type::varbool()); nonfalse[i] = uo; } ArrayLit* al = new ArrayLit(Location().introduce(),nonfalse); al->type(Type::varbool(1)); args.push_back(al); Call* ret = new Call(Location().introduce(),constants().ids.exists,args); ret->decl(env.model->matchFn(env, ret, false)); ret->type(ret->decl()->rtype(env, args, false)); assert(ret->decl()); KeepAlive ka(ret); GC::unlock(); return flat_exp(env,nctx,ret,b,constants().var_true).r; } } } } TypeInst* eval_typeinst(EnvI& env, VarDecl* vd) { bool hasTiVars = vd->ti()->domain() && vd->ti()->domain()->isa(); for (unsigned int i=0; iti()->ranges().size(); i++) { hasTiVars = hasTiVars || (vd->ti()->ranges()[i]->domain() && vd->ti()->ranges()[i]->domain()->isa()); } if (hasTiVars) { assert(vd->e()); if (vd->e()->type().dim()==0) return new TypeInst(Location().introduce(),vd->e()->type()); ArrayLit* al = eval_array_lit(env,vd->e()); std::vector dims(al->dims()); for (unsigned int i=0; imin(i),al->max(i)))); } return new TypeInst(Location().introduce(), vd->e()->type(), dims, eval_par(env,vd->ti()->domain())); } else { std::vector dims(vd->ti()->ranges().size()); for (unsigned int i=0; iti()->ranges().size(); i++) { if (vd->ti()->ranges()[i]->domain()) { IntSetVal* isv = eval_intset(env,vd->ti()->ranges()[i]->domain()); if (isv->size() > 1) throw EvalError(env, vd->ti()->ranges()[i]->domain()->loc(), "array index set must be contiguous range"); SetLit* sl = new SetLit(vd->ti()->ranges()[i]->loc(),isv); sl->type(Type::parsetint()); dims[i] = new TypeInst(vd->ti()->ranges()[i]->loc(), Type(),sl); } else { dims[i] = new TypeInst(vd->ti()->ranges()[i]->loc(), Type(), NULL); } } Type t = (vd->e() && !vd->e()->type().isbot()) ? vd->e()->type() : vd->ti()->type(); return new TypeInst(vd->ti()->loc(), t, dims, eval_par(env,vd->ti()->domain())); } } bool isBuiltin(FunctionI* decl) { return (decl->loc().filename() == "builtins.mzn" || decl->loc().filename().endsWith("/builtins.mzn") || decl->loc().filename() == "stdlib.mzn" || decl->loc().filename().endsWith("/stdlib.mzn") || decl->loc().filename() == "flatzinc_builtins.mzn" || decl->loc().filename().endsWith("/flatzinc_builtins.mzn")); } KeepAlive flat_cv_exp(EnvI& env, Ctx ctx, Expression* e) { GCLock lock; if (e->type().ispar() && !e->type().cv()) { return eval_par(env, e); } if (e->type().isvar()) { EE ee = flat_exp(env, ctx, e, NULL,NULL); if (isfalse(env, ee.b())) throw FlatteningError(env, e->loc(), "cannot flatten partial function in this position"); return ee.r(); } switch (e->eid()) { case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_BOOLLIT: case Expression::E_STRINGLIT: case Expression::E_TIID: case Expression::E_VARDECL: case Expression::E_TI: case Expression::E_ANON: assert(false); return NULL; case Expression::E_ID: { Id* id = e->cast(); return flat_cv_exp(env, ctx, id->decl()->e()); } case Expression::E_SETLIT: { SetLit* sl = e->cast(); if (sl->isv() || sl->fsv()) return sl; std::vector es(sl->v().size()); GCLock lock; for (unsigned int i=0; iv().size(); i++) { es[i] = flat_cv_exp(env, ctx, sl->v()[i])(); } SetLit* sl_ret = new SetLit(Location().introduce(),es); Type t = sl->type(); t.cv(false); sl_ret->type(t); return eval_par(env, sl_ret); } case Expression::E_ARRAYLIT: { ArrayLit* al = e->cast(); std::vector es(al->size()); GCLock lock; for (unsigned int i=0; isize(); i++) { es[i] = flat_cv_exp(env, ctx, (*al)[i])(); } std::vector > dims(al->dims()); for (int i=0; idims(); i++) { dims[i] = std::make_pair(al->min(i), al->max(i)); } Expression* al_ret = eval_par(env, new ArrayLit(Location().introduce(),es,dims)); Type t = al->type(); t.cv(false); al_ret->type(t); return al_ret; } case Expression::E_ARRAYACCESS: { ArrayAccess* aa = e->cast(); GCLock lock; Expression* av = flat_cv_exp(env, ctx, aa->v())(); std::vector idx(aa->idx().size()); for (unsigned int i=0; iidx().size(); i++) { idx[i] = flat_cv_exp(env, ctx, aa->idx()[i])(); } ArrayAccess* aa_ret = new ArrayAccess(Location().introduce(),av,idx); Type t = aa->type(); t.cv(false); aa_ret->type(t); return eval_par(env, aa_ret); } case Expression::E_COMP: { Comprehension* c = e->cast(); GCLock lock; class EvalFlatCvExp { public: Ctx ctx; EvalFlatCvExp(Ctx& ctx0) : ctx(ctx0) {} typedef Expression* ArrayVal; Expression* e(EnvI& env, Expression* e) { return flat_cv_exp(env,ctx,e)(); } static Expression* exp(Expression* e) { return e; } Expression* flatten(EnvI& env, Expression* e0) { return flat_exp(env,Ctx(),e0,NULL,constants().var_true).r(); } } eval(ctx); std::vector a = eval_comp(env,eval,c); Type t = Type::bot(); bool allPar = true; for (unsigned int i=0; itype(); if (!a[i]->type().ispar()) allPar = false; } if (!allPar) t.ti(Type::TI_VAR); if (c->set()) t.st(Type::ST_SET); else t.dim(c->type().dim()); t.cv(false); if (c->set()) { if (c->type().ispar() && allPar) { SetLit* sl = new SetLit(c->loc().introduce(), a); sl->type(t); Expression* slr = eval_par(env,sl); slr->type(t); return slr; } else { throw InternalError("var set comprehensions not supported yet"); } } else { ArrayLit* alr = new ArrayLit(Location().introduce(),a); alr->type(t); alr->flat(true); return alr; } } case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { KeepAlive ka = flat_cv_exp(env,ctx,ite->e_if(i)); if (eval_bool(env,ka())) return flat_cv_exp(env,ctx,ite->e_then(i)); } return flat_cv_exp(env,ctx,ite->e_else()); } case Expression::E_BINOP: { BinOp* bo = e->cast(); if (bo->op() == BOT_AND) { GCLock lock; Expression* lhs = flat_cv_exp(env, ctx, bo->lhs())(); if (!eval_bool(env, lhs)) { return constants().lit_false; } return eval_par(env, flat_cv_exp(env, ctx, bo->rhs())()); } else if (bo->op() == BOT_OR) { GCLock lock; Expression* lhs = flat_cv_exp(env, ctx, bo->lhs())(); if (eval_bool(env, lhs)) { return constants().lit_true; } return eval_par(env, flat_cv_exp(env, ctx, bo->rhs())()); } GCLock lock; BinOp* nbo = new BinOp(bo->loc().introduce(),flat_cv_exp(env, ctx, bo->lhs())(),bo->op(),flat_cv_exp(env, ctx, bo->rhs())()); nbo->type(bo->type()); nbo->decl(bo->decl()); return eval_par(env, nbo); } case Expression::E_UNOP: { UnOp* uo = e->cast(); GCLock lock; UnOp* nuo = new UnOp(uo->loc(), uo->op(), flat_cv_exp(env, ctx, uo->e())()); nuo->type(uo->type()); return eval_par(env, nuo); } case Expression::E_CALL: { Call* c = e->cast(); if (c->id()=="mzn_in_root_context") { return constants().boollit(ctx.b==C_ROOT); } if (ctx.b==C_ROOT && c->decl()->e() && c->decl()->e()->isa()) { bool allBool = true; for (unsigned int i=0; in_args(); i++) { if (c->arg(i)->type().bt()!=Type::BT_BOOL) { allBool = false; break; } } if (allBool) { return c->decl()->e(); } } std::vector args(c->n_args()); GCLock lock; for (unsigned int i=0; in_args(); i++) { args[i] = flat_cv_exp(env, ctx, c->arg(i))(); } Call* nc = new Call(c->loc(), c->id(), args); nc->decl(c->decl()); nc->type(c->type()); return eval_par(env, nc); } case Expression::E_LET: { Let* l = e->cast(); l->pushbindings(); KeepAlive ret = flat_cv_exp(env, ctx, l->in()); l->popbindings(); return ret; } } throw InternalError("internal error"); } class ItemTimer { public: typedef std::map,std::chrono::high_resolution_clock::duration> TimingMap; ItemTimer(const Location& loc, TimingMap* tm) : _loc(loc), _tm(tm), _start(std::chrono::high_resolution_clock::now()) {} ~ItemTimer(void) { if (_tm) { std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now(); int line = _loc.first_line(); TimingMap::iterator it = _tm->find(std::make_pair(_loc.filename().str(),line)); if (it != _tm->end()) { it->second += end-_start; } else { _tm->insert(std::make_pair(std::make_pair(_loc.filename().str(),line),end-_start)); } } } private: const Location& _loc; TimingMap* _tm; std::chrono::high_resolution_clock::time_point _start; }; void flatten(Env& e, FlatteningOptions opt) { ItemTimer::TimingMap timing_map_o; ItemTimer::TimingMap* timing_map = opt.detailedTiming ? &timing_map_o : nullptr; try { EnvI& env = e.envi(); env.fopts = opt; bool onlyRangeDomains = false; if ( opt.onlyRangeDomains ) { onlyRangeDomains = true; // compulsory } else { GCLock lock; Call* check_only_range = new Call(Location(),"mzn_check_only_range_domains", std::vector()); check_only_range->type(Type::parbool()); check_only_range->decl(env.model->matchFn(e.envi(), check_only_range, false)); onlyRangeDomains = eval_bool(e.envi(), check_only_range); } bool hadSolveItem = false; // Flatten main model class FV : public ItemVisitor { public: EnvI& env; bool& hadSolveItem; ItemTimer::TimingMap* timing_map; FV(EnvI& env0, bool& hadSolveItem0, ItemTimer::TimingMap* timing_map0) : env(env0), hadSolveItem(hadSolveItem0), timing_map(timing_map0) {} bool enter(Item* i) { return !(i->isa() && env.failed()); } void vVarDeclI(VarDeclI* v) { ItemTimer item_timer(v->loc(), timing_map); v->e()->ann().remove(constants().ann.output_var); v->e()->ann().removeCall(constants().ann.output_array); if (v->e()->ann().contains(constants().ann.output_only)) return; if (v->e()->type().ispar() && !v->e()->type().isopt() && !v->e()->type().cv() && v->e()->type().dim() > 0 && v->e()->ti()->domain()==NULL && (v->e()->type().bt()==Type::BT_INT || v->e()->type().bt()==Type::BT_FLOAT)) { // Compute bounds for array literals CallStackItem csi(env,v->e()); GCLock lock; ArrayLit* al = eval_array_lit(env, v->e()->e()); v->e()->e(al); checkIndexSets(env,v->e(), v->e()->e()); if (v->e()->type().bt()==Type::BT_INT && v->e()->type().st()==Type::ST_PLAIN) { IntVal lb = IntVal::infinity(); IntVal ub = -IntVal::infinity(); for (unsigned int i=0; isize(); i++) { IntVal vi = eval_int(env, (*al)[i]); lb = std::min(lb, vi); ub = std::max(ub, vi); } GCLock lock; //v->e()->ti()->domain(new SetLit(Location().introduce(), IntSetVal::a(lb, ub))); //v->e()->ti()->setComputedDomain(true); setComputedDomain(env, v->e(), new SetLit(Location().introduce(), IntSetVal::a(lb, ub)), true); } else if (v->e()->type().bt()==Type::BT_FLOAT && v->e()->type().st()==Type::ST_PLAIN) { FloatVal lb = FloatVal::infinity(); FloatVal ub = -FloatVal::infinity(); for (unsigned int i=0; isize(); i++) { FloatVal vi = eval_float(env, (*al)[i]); lb = std::min(lb, vi); ub = std::max(ub, vi); } GCLock lock; //v->e()->ti()->domain(new SetLit(Location().introduce(), FloatSetVal::a(lb, ub))); //v->e()->ti()->setComputedDomain(true); setComputedDomain(env, v->e(), new SetLit(Location().introduce(), FloatSetVal::a(lb, ub)), true); } } else if (v->e()->type().isvar() || v->e()->type().isann()) { (void) flatten_id(env,Ctx(),v->e()->id(),NULL,constants().var_true,true); } else { if (v->e()->e()==NULL) { if (!v->e()->type().isann()) throw EvalError(env, v->e()->loc(), "Undefined parameter", v->e()->id()->v()); } else { CallStackItem csi(env,v->e()); GCLock lock; Location v_loc = v->e()->e()->loc(); if (!v->e()->e()->type().cv()) { v->e()->e(eval_par(env,v->e()->e())); } else { EE ee = flat_exp(env, Ctx(), v->e()->e(), NULL, constants().var_true); v->e()->e(ee.r()); } if (v->e()->type().dim() > 0) { checkIndexSets(env,v->e(), v->e()->e()); if (v->e()->ti()->domain() != NULL) { ArrayLit* al = eval_array_lit(env,v->e()->e()); for (unsigned int i=0; isize(); i++) { if (!checkParDomain(env,(*al)[i], v->e()->ti()->domain())) { throw EvalError(env, v_loc, "parameter value out of range"); } } } } else { if (v->e()->ti()->domain() != NULL) { if (!checkParDomain(env,v->e()->e(), v->e()->ti()->domain())) { throw EvalError(env, v_loc, "parameter value out of range"); } } } } } } void vConstraintI(ConstraintI* ci) { ItemTimer item_timer(ci->loc(), timing_map); (void) flat_exp(env,Ctx(),ci->e(),constants().var_true,constants().var_true); } void vSolveI(SolveI* si) { if (hadSolveItem) throw FlatteningError(env,si->loc(), "Only one solve item allowed"); ItemTimer item_timer(si->loc(), timing_map); hadSolveItem = true; GCLock lock; SolveI* nsi = NULL; switch (si->st()) { case SolveI::ST_SAT: nsi = SolveI::sat(Location()); break; case SolveI::ST_MIN: { Ctx ctx; ctx.i = C_NEG; nsi = SolveI::min(Location().introduce(),flat_exp(env,ctx,si->e(),NULL,constants().var_true).r()); } break; case SolveI::ST_MAX: { Ctx ctx; ctx.i = C_POS; nsi = SolveI::max(Location().introduce(),flat_exp(env,Ctx(),si->e(),NULL,constants().var_true).r()); } break; } for (ExpressionSetIter it = si->ann().begin(); it != si->ann().end(); ++it) { nsi->ann().add(flat_exp(env,Ctx(),*it,NULL,constants().var_true).r()); } env.flat_addItem(nsi); } } _fv(env,hadSolveItem,timing_map); iterItems(_fv,e.model()); if (!hadSolveItem) { GCLock lock; e.envi().flat_addItem(SolveI::sat(Location().introduce())); } std::vector deletedVarDecls; // Create output model if (opt.keepOutputInFzn) { copyOutput(env); } else { createOutput(env, deletedVarDecls, opt.outputMode, opt.outputObjective, opt.outputOutputItem); } // Flatten remaining redefinitions Model& m = *e.flat(); int startItem = 0; int endItem = m.size()-1; FunctionI* int_lin_eq; { std::vector int_lin_eq_t(3); int_lin_eq_t[0] = Type::parint(1); int_lin_eq_t[1] = Type::varint(1); int_lin_eq_t[2] = Type::parint(0); GCLock lock; FunctionI* fi = env.model->matchFn(env, constants().ids.int_.lin_eq, int_lin_eq_t, false); int_lin_eq = (fi && fi->e()) ? fi : NULL; } FunctionI* array_bool_and; FunctionI* array_bool_or; FunctionI* array_bool_clause; FunctionI* array_bool_clause_reif; FunctionI* bool_xor; { std::vector array_bool_andor_t(2); array_bool_andor_t[0] = Type::varbool(1); array_bool_andor_t[1] = Type::varbool(0); GCLock lock; FunctionI* fi = env.model->matchFn(env, ASTString("array_bool_and"), array_bool_andor_t, false); array_bool_and = (fi && fi->e()) ? fi : NULL; fi = env.model->matchFn(env, ASTString("array_bool_or"), array_bool_andor_t, false); array_bool_or = (fi && fi->e()) ? fi : NULL; array_bool_andor_t[1] = Type::varbool(1); fi = env.model->matchFn(env, ASTString("bool_clause"), array_bool_andor_t, false); array_bool_clause = (fi && fi->e()) ? fi : NULL; array_bool_andor_t.push_back(Type::varbool()); fi = env.model->matchFn(env, ASTString("bool_clause_reif"), array_bool_andor_t, false); array_bool_clause_reif = (fi && fi->e()) ? fi : NULL; std::vector bool_xor_t(3); bool_xor_t[0] = Type::varbool(); bool_xor_t[1] = Type::varbool(); bool_xor_t[2] = Type::varbool(); fi = env.model->matchFn(env, constants().ids.bool_xor, bool_xor_t, false); bool_xor = (fi && fi->e()) ? fi : NULL; } std::vector removedItems; std::vector convertToRangeDomain; env.collectVarDecls(true); while (startItem <= endItem || !env.modifiedVarDecls.empty() || !convertToRangeDomain.empty()) { if (env.failed()) return; std::vector agenda; for (int i=startItem; i<=endItem; i++) { agenda.push_back(i); } for (unsigned int i=0; idyn_cast()) { if (vdi->removed()) continue; bool keptVariable = true; /// Look at constraints if (!isOutput(vdi->e())) { if (0e())) { const auto it = env.vo._m.find(vdi->e()->id()); if (env.vo._m.end()!=it) { bool hasRedundantOccurrenciesOnly = true; for (const auto& c: it->second) { if (auto constrI=c->dyn_cast()) if (auto call=constrI->e()->dyn_cast()) if (call->id()=="mzn_reverse_map_var") continue; // all good hasRedundantOccurrenciesOnly = false; break; } if (hasRedundantOccurrenciesOnly) { removedItems.push_back(vdi); env.flat_removeItem(vdi); env.vo.removeAllOccurrences(vdi->e()); keptVariable = false; for (const auto& c: it->second) { env.flat_removeItem(c); } } } } else { // 0 occurrencies if (vdi->e()->e() && vdi->e()->ti()->domain()) { if (vdi->e()->type().isvar() && vdi->e()->type().isbool() && !vdi->e()->type().isopt() && Expression::equal(vdi->e()->ti()->domain(),constants().lit_true)) { GCLock lock; ConstraintI* ci = new ConstraintI(vdi->loc(),vdi->e()->e()); if (vdi->e()->introduced()) { removedItems.push_back(vdi); env.flat_removeItem(vdi); keptVariable = false; } else { vdi->e()->e(NULL); } env.flat_addItem(ci); } else if (vdi->e()->type().ispar() || vdi->e()->ti()->computedDomain()) { removedItems.push_back(vdi); keptVariable = false; } } else { removedItems.push_back(vdi); env.flat_removeItem(vdi); keptVariable = false; } } } if (keptVariable && vdi->e()->type().dim() > 0 && vdi->e()->type().isvar()) { vdi->e()->ti()->domain(NULL); } if (keptVariable && vdi->e()->type().isint() && vdi->e()->type().isvar() && vdi->e()->ti()->domain() != NULL) { GCLock lock; IntSetVal* dom = eval_intset(env,vdi->e()->ti()->domain()); bool needRangeDomain = onlyRangeDomains; if (!needRangeDomain && dom->size() > 0) { if (dom->min(0).isMinusInfinity() || dom->max(dom->size()-1).isPlusInfinity()) needRangeDomain = true; } if (needRangeDomain) { if (doConvertToRangeDomain) { if (dom->min(0).isMinusInfinity() || dom->max(dom->size()-1).isPlusInfinity()) { TypeInst* nti = copy(env,vdi->e()->ti())->cast(); nti->domain(NULL); vdi->e()->ti(nti); if (dom->min(0).isFinite()) { std::vector args(2); args[0] = IntLit::a(dom->min(0)); args[1] = vdi->e()->id(); Call* call = new Call(Location().introduce(),constants().ids.int_.le,args); call->type(Type::varbool()); call->decl(env.model->matchFn(env, call, false)); env.flat_addItem(new ConstraintI(Location().introduce(), call)); } else if (dom->max(dom->size()-1).isFinite()) { std::vector args(2); args[0] = vdi->e()->id(); args[1] = IntLit::a(dom->max(dom->size()-1)); Call* call = new Call(Location().introduce(),constants().ids.int_.le,args); call->type(Type::varbool()); call->decl(env.model->matchFn(env, call, false)); env.flat_addItem(new ConstraintI(Location().introduce(), call)); } } else if (dom->size() > 1) { SetLit* newDom = new SetLit(Location().introduce(),IntSetVal::a(dom->min(0),dom->max(dom->size()-1))); TypeInst* nti = copy(env,vdi->e()->ti())->cast(); nti->domain(newDom); vdi->e()->ti(nti); } if (dom->size() > 1) { std::vector args(2); args[0] = vdi->e()->id(); args[1] = new SetLit(vdi->e()->loc(), dom); Call* call = new Call(vdi->e()->loc(),constants().ids.set_in,args); call->type(Type::varbool()); call->decl(env.model->matchFn(env, call, false)); // Give distinct call stack Annotation& ann = vdi->e()->ann(); Expression* tmp = call; if(Expression* mznpath_ann = ann.getCall(constants().ann.mzn_path)) { tmp = mznpath_ann->cast()->arg(0); } CallStackItem csi(env, tmp); env.flat_addItem(new ConstraintI(Location().introduce(), call)); } } else { convertToRangeDomain.push_back(i); } } } if (keptVariable && vdi->e()->type().isfloat() && vdi->e()->type().isvar() && vdi->e()->ti()->domain() != NULL) { GCLock lock; FloatSetVal* vdi_dom = eval_floatset(env, vdi->e()->ti()->domain()); FloatVal vmin = vdi_dom->min(); FloatVal vmax = vdi_dom->max(); if (vmin == -FloatVal::infinity() && vmax == FloatVal::infinity()) { vdi->e()->ti()->domain(NULL); } else if (vmin == -FloatVal::infinity()) { vdi->e()->ti()->domain(NULL); std::vector args(2); args[0] = vdi->e()->id(); args[1] = FloatLit::a(vmax); Call* call = new Call(Location().introduce(),constants().ids.float_.le,args); call->type(Type::varbool()); call->decl(env.model->matchFn(env, call, false)); env.flat_addItem(new ConstraintI(Location().introduce(), call)); } else if (vmax == FloatVal::infinity()) { vdi->e()->ti()->domain(NULL); std::vector args(2); args[0] = FloatLit::a(vmin); args[1] = vdi->e()->id(); Call* call = new Call(Location().introduce(),constants().ids.float_.le,args); call->type(Type::varbool()); call->decl(env.model->matchFn(env, call, false)); env.flat_addItem(new ConstraintI(Location().introduce(), call)); } else if (vdi_dom->size() > 1) { BinOp* dom_ranges = new BinOp(vdi->e()->ti()->domain()->loc().introduce(), FloatLit::a(vmin), BOT_DOTDOT, FloatLit::a(vmax)); vdi->e()->ti()->domain(dom_ranges); std::vector ranges; for (FloatSetRanges vdi_r(vdi_dom); vdi_r(); ++vdi_r) { ranges.push_back(FloatLit::a(vdi_r.min())); ranges.push_back(FloatLit::a(vdi_r.max())); } ArrayLit* al = new ArrayLit(Location().introduce(), ranges); al->type(Type::parfloat(1)); std::vector args(2); args[0] = vdi->e()->id(); args[1] = al; Call* call = new Call(Location().introduce(),constants().ids.float_.dom,args); call->type(Type::varbool()); call->decl(env.model->matchFn(env, call, false)); env.flat_addItem(new ConstraintI(Location().introduce(), call)); } } } } // rewrite some constraints if there are redefinitions for (int ai=0; aidyn_cast()) { VarDecl* vd = vdi->e(); if (!vdi->removed() && vd->e()) { bool isTrueVar = vd->type().isbool() && Expression::equal(vd->ti()->domain(), constants().lit_true); if (Call* c = vd->e()->dyn_cast()) { GCLock lock; Call* nc = NULL; if (c->id() == constants().ids.lin_exp) { if (int_lin_eq) { std::vector args(c->n_args()); ArrayLit* le_c = follow_id(c->arg(0))->cast(); std::vector nc_c(le_c->size()); for (unsigned int i=static_cast(nc_c.size()); i--;) nc_c[i] = (*le_c)[i]; nc_c.push_back(IntLit::a(-1)); args[0] = new ArrayLit(Location().introduce(),nc_c); args[0]->type(Type::parint(1)); ArrayLit* le_x = follow_id(c->arg(1))->cast(); std::vector nx(le_x->size()); for (unsigned int i=static_cast(nx.size()); i--;) nx[i] = (*le_x)[i]; nx.push_back(vd->id()); args[1] = new ArrayLit(Location().introduce(),nx); args[1]->type(Type::varint(1)); IntVal d = c->arg(2)->cast()->v(); args[2] = IntLit::a(-d); args[2]->type(Type::parint(0)); nc = new Call(c->loc().introduce(),ASTString("int_lin_eq"),args); nc->type(Type::varbool()); nc->decl(int_lin_eq); } } else if (c->id() == constants().ids.exists) { if (array_bool_or) { std::vector args(2); args[0] = c->arg(0); args[1] = vd->id(); nc = new Call(c->loc().introduce(),array_bool_or->id(),args); nc->type(Type::varbool()); nc->decl(array_bool_or); } } else if (!isTrueVar && c->id() == constants().ids.forall) { if (array_bool_and) { std::vector args(2); args[0] = c->arg(0); args[1] = vd->id(); nc = new Call(c->loc().introduce(),array_bool_and->id(),args); nc->type(Type::varbool()); nc->decl(array_bool_and); } } else if (isTrueVar && c->id() == constants().ids.clause && array_bool_clause) { std::vector args(2); args[0] = c->arg(0); args[1] = c->arg(1); nc = new Call(c->loc().introduce(),array_bool_clause->id(),args); nc->type(Type::varbool()); nc->decl(array_bool_clause); } else if (c->id() == constants().ids.clause && array_bool_clause_reif) { std::vector args(3); args[0] = c->arg(0); args[1] = c->arg(1); args[2] = vd->id(); nc = new Call(c->loc().introduce(),array_bool_clause_reif->id(),args); nc->type(Type::varbool()); nc->decl(array_bool_clause_reif); } else { if (isTrueVar) { FunctionI* decl = env.model->matchFn(env,c,false); env.cse_map_remove(c); if (decl->e() || c->id() == constants().ids.forall) { if (decl->e()) addPathAnnotation(env, decl->e()); c->decl(decl); nc = c; } } else { std::vector args(c->n_args()); for (unsigned int i=static_cast(args.size()); i--;) args[i] = c->arg(i); args.push_back(vd->id()); ASTString cid = c->id(); if (cid == constants().ids.clause && array_bool_clause_reif) { nc = new Call(c->loc().introduce(),array_bool_clause_reif->id(),args); nc->type(Type::varbool()); nc->decl(array_bool_clause_reif); } else { FunctionI* decl = nullptr; if (c->type().isbool() && vd->type().isbool()) { if (env.fopts.enable_imp && vd->ann().contains(constants().ctx.pos)) { cid = env.halfReifyId(c->id()); decl = env.model->matchFn(env, cid, args, false); if (decl==nullptr) { cid = env.reifyId(c->id()); decl = env.model->matchFn(env, cid, args, false); } } else { cid = env.reifyId(c->id()); decl = env.model->matchFn(env, cid, args, false); } if (decl==nullptr) { throw FlatteningError(env,c->loc(),"'"+c->id().str()+"' is used in a reified context but no reified version is available"); } } else { decl = env.model->matchFn(env,cid,args,false); } if (decl && decl->e()) { addPathAnnotation(env, decl->e()); nc = new Call(c->loc().introduce(),cid,args); nc->type(Type::varbool()); nc->decl(decl); } } } } if (nc != NULL) { CollectDecls cd(env.vo,deletedVarDecls,vdi); topDown(cd,c); vd->e(NULL); // Need to remove right hand side from CSE map, otherwise // flattening of nc could assume c has already been flattened // to vd env.cse_map_remove(c); /// TODO: check if removing variables here makes sense: // if (!isOutput(vd) && env.vo.occurrences(vd)==0) { // removedItems.push_back(vdi); // } if (nc != c) { makeDefinedVar(vd, nc); } StringLit* vsl = getLongestMznPathAnnotation(env, vdi->e()); StringLit* csl = getLongestMznPathAnnotation(env, c); CallStackItem* vsi=NULL; CallStackItem* csi=NULL; if(vsl) vsi = new CallStackItem(env, vsl); if(csl) csi = new CallStackItem(env, csl); Location orig_loc = nc->loc(); if (csl) { std::string loc(csl->v().str()); size_t sep = loc.find('|'); std::string filename = loc.substr(0, sep); std::string start_line_s = loc.substr(sep+1, loc.find('|',sep+1)-sep-1); int start_line = std::stoi(start_line_s); Location new_loc(ASTString(filename), start_line, 0, start_line, 0); orig_loc = new_loc; } ItemTimer item_timer(orig_loc, timing_map); (void) flat_exp(env, Ctx(), nc, constants().var_true, constants().var_true); if(csi) delete csi; if(vsi) delete vsi; } } } } else if (ConstraintI* ci = m[i]->dyn_cast()) { if (!ci->removed()) { if (Call* c = ci->e()->dyn_cast()) { GCLock lock; Call* nc = NULL; if (c->id() == constants().ids.exists) { if (array_bool_or) { std::vector args(2); args[0] = c->arg(0); args[1] = constants().lit_true; nc = new Call(c->loc().introduce(),array_bool_or->id(),args); nc->type(Type::varbool()); nc->decl(array_bool_or); } } else if (c->id() == constants().ids.forall) { if (array_bool_and) { std::vector args(2); args[0] = c->arg(0); args[1] = constants().lit_true; nc = new Call(c->loc().introduce(),array_bool_and->id(),args); nc->type(Type::varbool()); nc->decl(array_bool_and); } } else if (c->id() == constants().ids.clause) { if (array_bool_clause) { std::vector args(2); args[0] = c->arg(0); args[1] = c->arg(1); nc = new Call(c->loc().introduce(),array_bool_clause->id(),args); nc->type(Type::varbool()); nc->decl(array_bool_clause); } } else if (c->id() == constants().ids.bool_xor) { if (bool_xor) { std::vector args(3); args[0] = c->arg(0); args[1] = c->arg(1); args[2] = c->n_args()==2 ? constants().lit_true : c->arg(2); nc = new Call(c->loc().introduce(),bool_xor->id(),args); nc->type(Type::varbool()); nc->decl(bool_xor); } } else { FunctionI* decl = env.model->matchFn(env,c,false); if (decl && decl->e()) { nc = c; nc->decl(decl); } } if (nc != NULL) { CollectDecls cd(env.vo,deletedVarDecls,ci); topDown(cd,c); ci->e(constants().lit_true); env.flat_removeItem(i); StringLit* sl = getLongestMznPathAnnotation(env, c); CallStackItem* csi=NULL; if(sl) csi = new CallStackItem(env, sl); ItemTimer item_timer(nc->loc(), timing_map); (void) flat_exp(env, Ctx(), nc, constants().var_true, constants().var_true); if(csi) delete csi; } } } } } startItem = endItem+1; endItem = m.size()-1; } for (unsigned int i=0; ie())==0) { CollectDecls cd(env.vo,deletedVarDecls,removedItems[i]); topDown(cd,removedItems[i]->e()->e()); env.flat_removeItem(removedItems[i]); } } // Add redefinitions for output variables that may have been redefined since createOutput for (unsigned int i=0; isize(); i++) { if (VarDeclI* vdi = (*env.output)[i]->dyn_cast()) { IdMap::iterator it; if (vdi->e()->e()==NULL && (it = env.reverseMappers.find(vdi->e()->id())) != env.reverseMappers.end()) { GCLock lock; Call* rhs = copy(env,env.cmap,it->second())->cast(); std::vector tv(rhs->n_args()); for (unsigned int i=rhs->n_args(); i--;) { tv[i] = rhs->arg(i)->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = env.output->matchFn(env, rhs->id(), tv, false); Type t; if (decl==NULL) { FunctionI* origdecl = env.model->matchFn(env, rhs->id(), tv, false); if (origdecl == NULL) { throw FlatteningError(env,rhs->loc(),"function "+rhs->id().str()+" is used in output, par version needed"); } if (!isBuiltin(origdecl)) { decl = copy(env,env.cmap,origdecl)->cast(); CollectOccurrencesE ce(env.output_vo,decl); topDown(ce, decl->e()); topDown(ce, decl->ti()); for (unsigned int i = decl->params().size(); i--;) topDown(ce, decl->params()[i]); env.output->registerFn(env, decl); env.output->addItem(decl); } else { decl = origdecl; } } rhs->decl(decl); outputVarDecls(env,vdi,rhs); removeIsOutput(vdi->e()->flat()); vdi->e()->e(rhs); } } } while (!deletedVarDecls.empty()) { VarDecl* cur = deletedVarDecls.back(); deletedVarDecls.pop_back(); if (env.vo.occurrences(cur) == 0 && !isOutput(cur)) { if (CollectDecls::varIsFree(cur)) { IdMap::iterator cur_idx = env.vo.idx.find(cur->id()); if (cur_idx != env.vo.idx.end() && !m[cur_idx->second]->removed()) { CollectDecls cd(env.vo,deletedVarDecls,m[cur_idx->second]->cast()); topDown(cd,cur->e()); env.flat_removeItem(cur_idx->second); } } } } if (!opt.keepOutputInFzn) { finaliseOutput(env, deletedVarDecls); } for (unsigned int i=0; idyn_cast()) { if (Call* c = ci->e()->dyn_cast()) { if (c->decl()==constants().var_redef) { CollectDecls cd(env.vo,deletedVarDecls,ci); topDown(cd,c); env.flat_removeItem(i); } } } } while (!deletedVarDecls.empty()) { VarDecl* cur = deletedVarDecls.back(); deletedVarDecls.pop_back(); if (env.vo.occurrences(cur) == 0 && !isOutput(cur)) { if (CollectDecls::varIsFree(cur)) { IdMap::iterator cur_idx = env.vo.idx.find(cur->id()); if (cur_idx != env.vo.idx.end() && !m[cur_idx->second]->removed()) { CollectDecls cd(env.vo,deletedVarDecls,m[cur_idx->second]->cast()); topDown(cd,cur->e()); env.flat_removeItem(cur_idx->second); } } } } cleanupOutput(env); } catch (ModelInconsistent&) { } if (opt.detailedTiming) { e.envi().outstream << "% Compilation profile (file,line,milliseconds)\n"; if (opt.collect_mzn_paths) { e.envi().outstream << "% (time is allocated to toplevel item)\n"; } else { e.envi().outstream << "% (locations are approximate, use --keep-paths to allocate times to toplevel items)\n"; } for (auto& entry : *timing_map) { std::chrono::milliseconds time_taken = std::chrono::duration_cast(entry.second); if (time_taken > std::chrono::milliseconds(0)) { e.envi().outstream << "%%%mzn-stat: profiling=[\"" << entry.first.first << "\"," << entry.first.second << "," << time_taken.count() << "]\n"; } } e.envi().outstream << "%%%mzn-stat-end\n"; } } void clearInternalAnnotations(Expression* e) { e->ann().remove(constants().ann.promise_total); e->ann().remove(constants().ann.maybe_partial); e->ann().remove(constants().ann.add_to_output); e->ann().remove(constants().ann.rhs_from_assignment); // Remove defines_var(x) annotation where x is par std::vector removeAnns; for (ExpressionSetIter anns = e->ann().begin(); anns != e->ann().end(); ++anns) { if (Call* c = (*anns)->dyn_cast()) { if (c->id() == constants().ann.defines_var && c->arg(0)->type().ispar()) { removeAnns.push_back(c); } } } for (unsigned int i=0; iann().remove(removeAnns[i]); } } std::vector cleanup_vardecl(EnvI& env, VarDeclI* vdi, VarDecl* vd) { std::vector added_constraints; // In FlatZinc par variables have RHSs, not domains if (vd->type().ispar()) { vd->ann().clear(); vd->introduced(false); vd->ti()->domain(NULL); } // In FlatZinc the RHS of a VarDecl must be a literal, Id or empty // Example: // var 1..5: x = function(y) // becomes: // var 1..5: x; // relation(x, y); if (vd->type().isvar() && vd->type().isbool()) { bool is_fixed = ( vd->ti()->domain() != NULL ); if (Expression::equal(vd->ti()->domain(),constants().lit_true)) { // Ex: var true: b = e() // Store RHS Expression* ve = vd->e(); vd->e(constants().lit_true); vd->ti()->domain(NULL); // Ex: var bool: b = true // If vd had a RHS if (ve != NULL) { if (Call* vcc = ve->dyn_cast()) { // Convert functions to relations: // exists([x]) => array_bool_or([x],true) // forall([x]) => array_bool_and([x],true) // clause([x]) => bool_clause([x]) ASTString cid; std::vector args; if (vcc->id() == constants().ids.exists) { cid = constants().ids.array_bool_or; args.push_back(vcc->arg(0)); args.push_back(constants().lit_true); } else if (vcc->id() == constants().ids.forall) { cid = constants().ids.array_bool_and; args.push_back(vcc->arg(0)); args.push_back(constants().lit_true); } else if (vcc->id() == constants().ids.clause) { cid = constants().ids.bool_clause; args.push_back(vcc->arg(0)); args.push_back(vcc->arg(1)); } if (args.size()==0) { // Post original RHS as stand alone constraint ve = vcc; } else { // Create new call, retain annotations from original RHS Call* nc = new Call(vcc->loc().introduce(),cid,args); nc->type(vcc->type()); nc->ann().merge(vcc->ann()); ve = nc; } } else if (Id* id = ve->dyn_cast()) { if (id->decl()->ti()->domain() != constants().lit_true) { // Inconsistent assignment: post bool_eq(y, true) std::vector args(2); args[0] = id; args[1] = constants().lit_true; GCLock lock; ve = new Call(Location().introduce(),constants().ids.bool_eq,args); } else { // Don't post this ve = constants().lit_true; } } // Post new constraint if (ve != constants().lit_true) { clearInternalAnnotations(ve); added_constraints.push_back(ve); } } } else { // Ex: var false: b = e() if (vd->e() != NULL) { if (vd->e()->eid()==Expression::E_CALL) { // Convert functions to relations: // var false: b = exists([x]) => array_bool_or([x], b) // var false: b = forall([x]) => array_bool_and([x], b) // var false: b = clause([x]) => bool_clause_reif([x], b) const Call* c = vd->e()->cast(); GCLock lock; vd->e(NULL); ASTString cid; std::vector args(c->n_args()); for (unsigned int i=args.size(); i--;) args[i] = c->arg(i); if (is_fixed) { args.push_back(constants().lit_false); } else { args.push_back(vd->id()); } if (c->id() == constants().ids.exists) { cid = constants().ids.array_bool_or; } else if (c->id() == constants().ids.forall) { cid = constants().ids.array_bool_and; } else if (c->id() == constants().ids.clause) { cid = constants().ids.bool_clause_reif; } else { if (env.fopts.enable_imp && vd->ann().contains(constants().ctx.pos)) { cid = env.halfReifyId(c->id()); if (env.model->matchFn(env, cid, args, false) == NULL) { cid = env.reifyId(c->id()); } } else { cid = env.reifyId(c->id()); } } Call * nc = new Call(c->loc().introduce(),cid,args); nc->type(c->type()); FunctionI* decl = env.model->matchFn(env, nc, false); if (decl==NULL) { throw FlatteningError(env,c->loc(),"'"+c->id().str()+"' is used in a reified context but no reified version is available"); } nc->decl(decl); if (!is_fixed) { makeDefinedVar(vd, nc); } nc->ann().merge(c->ann()); clearInternalAnnotations(nc); added_constraints.push_back(nc); } else { assert(vd->e()->eid() == Expression::E_ID || vd->e()->eid() == Expression::E_BOOLLIT); } } if (Expression::equal(vd->ti()->domain(),constants().lit_false)) { vd->ti()->domain(NULL); vd->e(constants().lit_false); } } if (vdi != NULL && is_fixed && env.vo.occurrences(vd)==0) { if (isOutput(vd)) { VarDecl* vd_output = (*env.output)[env.output_vo_flat.find(vd)]->cast()->e(); if (vd_output->e() == NULL) { vd_output->e(vd->e()); } } env.flat_removeItem(vdi); } } else if (vd->type().isvar() && vd->type().dim()==0) { // Int or Float var if (vd->e() != NULL) { if (const Call* cc = vd->e()->dyn_cast()) { // Remove RHS from vd vd->e(NULL); std::vector args(cc->n_args()); ASTString cid; if (cc->id() == constants().ids.lin_exp) { // a = lin_exp([1],[b],5) => int_lin_eq([1,-1],[b,a],-5):: defines_var(a) ArrayLit* le_c = follow_id(cc->arg(0))->cast(); std::vector nc(le_c->size()); for (unsigned int i=static_cast(nc.size()); i--;) nc[i] = (*le_c)[i]; if (le_c->type().bt()==Type::BT_INT) { cid = constants().ids.int_.lin_eq; nc.push_back(IntLit::a(-1)); args[0] = new ArrayLit(Location().introduce(),nc); args[0]->type(Type::parint(1)); ArrayLit* le_x = follow_id(cc->arg(1))->cast(); std::vector nx(le_x->size()); for (unsigned int i=static_cast(nx.size()); i--;) nx[i] = (*le_x)[i]; nx.push_back(vd->id()); args[1] = new ArrayLit(Location().introduce(),nx); args[1]->type(le_x->type()); IntVal d = cc->arg(2)->cast()->v(); args[2] = IntLit::a(-d); } else { // float cid = constants().ids.float_.lin_eq; nc.push_back(FloatLit::a(-1.0)); args[0] = new ArrayLit(Location().introduce(),nc); args[0]->type(Type::parfloat(1)); ArrayLit* le_x = follow_id(cc->arg(1))->cast(); std::vector nx(le_x->size()); for (unsigned int i=static_cast(nx.size()); i--;) nx[i] = (*le_x)[i]; nx.push_back(vd->id()); args[1] = new ArrayLit(Location().introduce(),nx); args[1]->type(le_x->type()); FloatVal d = cc->arg(2)->cast()->v(); args[2] = FloatLit::a(-d); } } else { if (cc->id() == "card") { // card is 'set_card' in old FlatZinc cid = constants().ids.set_card; } else { cid = cc->id(); } for (unsigned int i=static_cast(args.size()); i--;) args[i] = cc->arg(i); args.push_back(vd->id()); } Call* nc = new Call(cc->loc().introduce(),cid,args); nc->type(cc->type()); makeDefinedVar(vd, nc); nc->ann().merge(cc->ann()); clearInternalAnnotations(nc); added_constraints.push_back(nc); } else { // RHS must be literal or Id assert(vd->e()->eid() == Expression::E_ID || vd->e()->eid() == Expression::E_INTLIT || vd->e()->eid() == Expression::E_FLOATLIT || vd->e()->eid() == Expression::E_BOOLLIT || vd->e()->eid() == Expression::E_SETLIT); } } } else if (vd->type().dim() > 0) { // vd is an array // If RHS is an Id, follow id to RHS // a = [1,2,3]; b = a; // vd = b => vd = [1,2,3] if (!vd->e()->isa()) { vd->e(follow_id(vd->e())); } // If empty array or 1 indexed, continue if (vd->ti()->ranges().size() == 1 && vd->ti()->ranges()[0]->domain() != NULL && vd->ti()->ranges()[0]->domain()->isa()) { IntSetVal* isv = vd->ti()->ranges()[0]->domain()->cast()->isv(); if (isv && (isv->size()==0 || isv->min(0)==1)) return added_constraints; } // Array should be 1 indexed since ArrayLit is 1 indexed assert(vd->e() != NULL); ArrayLit* al = NULL; Expression* e = vd->e(); while (al==NULL) { switch (e->eid()) { case Expression::E_ARRAYLIT: al = e->cast(); break; case Expression::E_ID: e = e->cast()->decl()->e(); break; default: assert(false); } } al->make1d(); IntSetVal* isv = IntSetVal::a(1,al->length()); if (vd->ti()->ranges().size() == 1) { vd->ti()->ranges()[0]->domain(new SetLit(Location().introduce(),isv)); } else { std::vector r(1); r[0] = new TypeInst(vd->ti()->ranges()[0]->loc(), vd->ti()->ranges()[0]->type(), new SetLit(Location().introduce(),isv)); ASTExprVec ranges(r); TypeInst* ti = new TypeInst(vd->ti()->loc(),vd->ti()->type(),ranges,vd->ti()->domain()); vd->ti(ti); } } // Remove boolean context annotations used only on compilation vd->ann().remove(constants().ctx.mix); vd->ann().remove(constants().ctx.pos); vd->ann().remove(constants().ctx.neg); vd->ann().remove(constants().ctx.root); vd->ann().remove(constants().ann.promise_total); vd->ann().remove(constants().ann.add_to_output); vd->ann().remove(constants().ann.mzn_check_var); vd->ann().remove(constants().ann.rhs_from_assignment); vd->ann().removeCall(constants().ann.mzn_check_enum_var); return added_constraints; } Expression* cleanup_constraint(EnvI& env, std::unordered_set& globals, Expression* ce) { clearInternalAnnotations(ce); if (Call* vc = ce->dyn_cast()) { for (unsigned int i=0; in_args(); i++) { // Change array indicies to be 1 indexed if (ArrayLit* al = vc->arg(i)->dyn_cast()) { if (al->dims()>1 || al->min(0)!= 1) { al->make1d(); } } } // Convert functions to relations: // exists([x]) => array_bool_or([x],true) // forall([x]) => array_bool_and([x],true) // clause([x]) => bool_clause([x]) // bool_xor([x],[y]) => bool_xor([x],[y],true) if (vc->id() == constants().ids.exists) { GCLock lock; vc->id(constants().ids.array_bool_or); std::vector args(2); args[0] = vc->arg(0); args[1] = constants().lit_true; ASTExprVec argsv(args); vc->args(argsv); vc->decl(env.model->matchFn(env, vc, false)); } else if (vc->id() == constants().ids.forall) { GCLock lock; vc->id(constants().ids.array_bool_and); std::vector args(2); args[0] = vc->arg(0); args[1] = constants().lit_true; ASTExprVec argsv(args); vc->args(argsv); vc->decl(env.model->matchFn(env, vc, false)); } else if (vc->id() == constants().ids.clause) { GCLock lock; vc->id(constants().ids.bool_clause); vc->decl(env.model->matchFn(env, vc, false)); } else if (vc->id() == constants().ids.bool_xor && vc->n_args()==2) { GCLock lock; std::vector args(3); args[0] = vc->arg(0); args[1] = vc->arg(1); args[2] = constants().lit_true; ASTExprVec argsv(args); vc->args(argsv); vc->decl(env.model->matchFn(env, vc, false)); } // If vc->decl() is a solver builtin and has not been added to the // FlatZinc, add it if (vc->decl() && vc->decl() != constants().var_redef && !vc->decl()->from_stdlib() && globals.find(vc->decl())==globals.end()) { std::vector params(vc->decl()->params().size()); for (unsigned int i=0; idecl()->params()[i]; } GCLock lock; FunctionI* vc_decl_copy = new FunctionI(vc->decl()->loc(),vc->decl()->id(),vc->decl()->ti(),params,vc->decl()->e()); env.flat_addItem(vc_decl_copy); globals.insert(vc->decl()); } return ce; } else if (Id* id = ce->dyn_cast()) { // Ex: constraint b; => constraint bool_eq(b, true); std::vector args(2); args[0] = id; args[1] = constants().lit_true; GCLock lock; return new Call(Location().introduce(),constants().ids.bool_eq,args); } else if (BoolLit* bl = ce->dyn_cast()) { // Ex: true => delete; false => bool_eq(false, true); if (!bl->v()) { GCLock lock; std::vector args(2); args[0] = constants().lit_false; args[1] = constants().lit_true; Call* neq = new Call(Location().introduce(),constants().ids.bool_eq,args); return neq; } else { return NULL; } } else { return ce; } } void oldflatzinc(Env& e) { Model* m = e.flat(); // Mark annotations and optional variables for removal for (unsigned int i=0; isize(); i++) { Item* item = (*m)[i]; if(VarDeclI* vdi = item->dyn_cast()) { if(item->cast()->e()->type().ot() == Type::OT_OPTIONAL || item->cast()->e()->type().bt() == Type::BT_ANN) { e.envi().flat_removeItem(i); } } } EnvI& env = e.envi(); int msize = m->size(); // Predicate declarations of solver builtins std::unordered_set globals; // Record indices of VarDeclIs with Id RHS for sorting & unification std::vector declsWithIds; for (int i=0; iremoved()) continue; if (VarDeclI* vdi = (*m)[i]->dyn_cast()) { GCLock lock; VarDecl* vd = vdi->e(); std::vector added_constraints = cleanup_vardecl(e.envi(), vdi, vd); // Record whether this VarDecl is equal to an Id (aliasing) if (vd->e() && vd->e()->isa()) { declsWithIds.push_back(i); vdi->e()->payload(-static_cast(i)-1); } else { vdi->e()->payload(i); } for (auto nc : added_constraints) { Expression* new_ce = cleanup_constraint(e.envi(), globals, nc); if (new_ce) { e.envi().flat_addItem(new ConstraintI(Location().introduce(),new_ce)); } } } else if (ConstraintI* ci = (*m)[i]->dyn_cast()) { Expression* new_ce = cleanup_constraint(e.envi(), globals, ci->e()); if (new_ce) { ci->e(new_ce); } else { ci->remove(); } } else if (FunctionI* fi = (*m)[i]->dyn_cast()) { if (Let* let = Expression::dyn_cast(fi->e())) { GCLock lock; std::vector new_let; for (unsigned int i=0; ilet().size(); i++) { Expression* let_e = let->let()[i]; if (VarDecl* vd = let_e->dyn_cast()) { std::vector added_constraints = cleanup_vardecl(e.envi(), NULL, vd); new_let.push_back(vd); for (auto nc : added_constraints) new_let.push_back(nc); } else { Expression* new_ce = cleanup_constraint(e.envi(), globals, let_e); if (new_ce) { new_let.push_back(new_ce); } } } fi->e(new Let(let->loc(), new_let, let->in())); } } else if (SolveI* si = (*m)[i]->dyn_cast()) { if (si->e() && si->e()->type().ispar()) { // Introduce VarDecl if objective expression is par GCLock lock; TypeInst* ti = new TypeInst(Location().introduce(),si->e()->type(),NULL); VarDecl* constantobj = new VarDecl(Location().introduce(),ti,e.envi().genId(),si->e()); si->e(constantobj->id()); e.envi().flat_addItem(new VarDeclI(Location().introduce(),constantobj)); } } } // Sort VarDecls in FlatZinc so that VarDecls are declared before use std::vector sortedVarDecls(declsWithIds.size()); int vdCount = 0; for (unsigned int i=0; icast()->e(); std::vector stack; while (cur && cur->payload() < 0) { stack.push_back(cur->payload()); if (Id* id = cur->e()->dyn_cast()) { cur = id->decl(); } else { cur = NULL; } } for (unsigned int i=static_cast(stack.size()); i--;) { VarDeclI* vdi = (*m)[-stack[i]-1]->cast(); vdi->e()->payload(-vdi->e()->payload()-1); sortedVarDecls[vdCount++] = vdi; } } for (unsigned int i=0; icompact(); e.envi().output->compact(); for (IdMap::iterator it = env.vo._m.begin(); it != env.vo._m.end(); ++it) { std::vector toRemove; for (VarOccurrences::Items::iterator iit = it->second.begin(); iit != it->second.end(); ++iit) { if ((*iit)->removed()) { toRemove.push_back(*iit); } } for (unsigned int i=0; isecond.erase(toRemove[i]); } } class Cmp { public: bool operator() (Item* i, Item* j) { if (i->iid()==Item::II_FUN || j->iid()==Item::II_FUN) { if (i->iid()==j->iid()) return false; return i->iid()==Item::II_FUN; } if (i->iid()==Item::II_SOL) { assert(j->iid() != i->iid()); return false; } if (j->iid()==Item::II_SOL) { assert(j->iid() != i->iid()); return true; } if (i->iid()==Item::II_VD) { if (j->iid() != i->iid()) return true; if (i->cast()->e()->type().ispar() && j->cast()->e()->type().isvar()) return true; if (j->cast()->e()->type().ispar() && i->cast()->e()->type().isvar()) return false; if (i->cast()->e()->type().dim() == 0 && j->cast()->e()->type().dim() != 0) return true; if (i->cast()->e()->type().dim() != 0 && j->cast()->e()->type().dim() == 0) return false; if (i->cast()->e()->e()==NULL && j->cast()->e()->e() != NULL) return true; if (i->cast()->e()->e() && j->cast()->e()->e() && !i->cast()->e()->e()->isa() && j->cast()->e()->e()->isa()) return true; } return false; } } _cmp; // Perform final sorting std::stable_sort(m->begin(),m->end(),_cmp); } FlatModelStatistics statistics(Env& m) { Model* flat = m.flat(); FlatModelStatistics stats; stats.n_reif_ct = m.envi().n_reif_ct; stats.n_imp_ct = m.envi().n_imp_ct; stats.n_imp_del = m.envi().n_imp_del; stats.n_lin_del = m.envi().n_lin_del; for (unsigned int i=0; isize(); i++) { if (!(*flat)[i]->removed()) { if (VarDeclI* vdi = (*flat)[i]->dyn_cast()) { Type t = vdi->e()->type(); if (t.isvar() && t.dim()==0) { if (t.is_set()) stats.n_set_vars++; else if (t.isint()) stats.n_int_vars++; else if (t.isbool()) stats.n_bool_vars++; else if (t.isfloat()) stats.n_float_vars++; } } else if (ConstraintI* ci = (*flat)[i]->dyn_cast()) { if (Call* call = ci->e()->dyn_cast()) { if (call->id().endsWith("_reif")) { stats.n_reif_ct++; } else if (call->id().endsWith("_imp")) { stats.n_imp_ct++; } if (call->n_args() > 0) { Type all_t; for (unsigned int i=0; in_args(); i++) { Type t = call->arg(i)->type(); if (t.isvar()) { if (t.st()==Type::ST_SET) all_t = t; else if (t.bt()==Type::BT_FLOAT && all_t.st()!=Type::ST_SET) all_t = t; else if (t.bt()==Type::BT_INT && all_t.bt()!=Type::BT_FLOAT && all_t.st()!=Type::ST_SET) all_t = t; else if (t.bt()==Type::BT_BOOL && all_t.bt()!=Type::BT_INT && all_t.bt()!=Type::BT_FLOAT && all_t.st()!=Type::ST_SET) all_t = t; } } if (all_t.isvar()) { if (all_t.st()==Type::ST_SET) stats.n_set_ct++; else if (all_t.bt()==Type::BT_INT) stats.n_int_ct++; else if (all_t.bt()==Type::BT_BOOL) stats.n_bool_ct++; else if (all_t.bt()==Type::BT_FLOAT) stats.n_float_ct++; } } } } } } return stats; } } libminizinc-2.4.2/lib/flatten/000077500000000000000000000000001360574160400162375ustar00rootroot00000000000000libminizinc-2.4.2/lib/flatten/flat_exp.cpp000066400000000000000000000104701360574160400205470ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include namespace MiniZinc { CallArgItem::CallArgItem(EnvI& env0) : env(env0) { env.idStack.push_back(static_cast(env.callStack.size())); } CallArgItem::~CallArgItem(void) { env.idStack.pop_back(); } Expression* createDummyValue(EnvI& env, const Type& t) { if (t.dim()>0) { Expression* ret = new ArrayLit(Location().introduce(), std::vector()); Type ret_t = t; ret_t.ti(Type::TI_PAR); ret->type(ret_t); return ret; } if (t.st()==Type::ST_SET) { Expression* ret = new SetLit(Location().introduce(), std::vector()); Type ret_t = t; ret_t.ti(Type::TI_PAR); ret->type(ret_t); return ret; } switch (t.bt()) { case Type::BT_INT: return IntLit::a(0); case Type::BT_BOOL: return constants().boollit(false); case Type::BT_FLOAT: return FloatLit::a(0); case Type::BT_STRING: return new StringLit(Location().introduce(), ""); case Type::BT_ANN: return constants().ann.promise_total; default: return NULL; } } EE flatten_error(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b) { throw InternalError("invalid expression encountered during compilation"); } #ifndef NDEBUG void mzn_break_here(Expression* e) { std::cerr << "% mzn_break_here: " << *e << "\n"; } #endif typedef EE (*ExprFlattener) (EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b); EE flatten_setlit(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b); EE flatten_id(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b); EE flatten_anon(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b); EE flatten_arraylit(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b); EE flatten_arrayaccess(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b); EE flatten_comp(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b); EE flatten_ite(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b); EE flatten_binop(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b); EE flatten_unop(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b); EE flatten_call(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b); EE flatten_vardecl(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b); EE flatten_let(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b); EE flatten_par(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b); EE flatten_error(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b); EE flat_exp(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b) { if (e==NULL) return EE(); #ifndef NDEBUG Annotation& e_ann = e->ann(); if(e_ann.contains(constants().ann.mzn_break_here)) mzn_break_here(e); #endif assert(!e->type().isunknown()); static const ExprFlattener flattener_dispatch[] = { &flatten_par, // par expressions &flatten_error, // E_INTLIT &flatten_error, // E_FLOATLIT &flatten_setlit, // E_SETLIT &flatten_error, // E_BOOLLIT &flatten_error, // E_STRINGLIT &flatten_id, // E_ID &flatten_anon, // E_ANON &flatten_arraylit, // E_ARRAYLIT &flatten_arrayaccess, // E_ARRAYACCESS &flatten_comp, // E_COMP &flatten_ite, // E_ITE &flatten_binop, // E_BINOP &flatten_unop, // E_UNOP &flatten_call, // E_CALL &flatten_vardecl, // E_VARDECL &flatten_let, // E_LET &flatten_error, // E_TI &flatten_error // E_TIID }; int dispatch = (e->type().ispar() && !e->isa() && !e->isa() && e->type().bt()!=Type::BT_ANN) ? 0 : e->eid()-Expression::E_INTLIT+1; return flattener_dispatch[dispatch](env, ctx, e, r, b); } } libminizinc-2.4.2/lib/flatten/flatten_anon.cpp000066400000000000000000000016241360574160400214160ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include namespace MiniZinc { EE flatten_anon(EnvI& env,Ctx ctx, Expression* e, VarDecl* r, VarDecl* b) { CallStackItem _csi(env,e); EE ret; AnonVar* av = e->cast(); if (av->type().isbot()) { throw InternalError("type of anonymous variable could not be inferred"); } GCLock lock; VarDecl* vd = newVarDecl(env, Ctx(), new TypeInst(Location().introduce(), av->type()), NULL, NULL, NULL); ret.b = bind(env, Ctx(), b, constants().lit_true); ret.r = bind(env, ctx, r, vd->id()); return ret; } } libminizinc-2.4.2/lib/flatten/flatten_arrayaccess.cpp000066400000000000000000000233531360574160400227660ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include namespace MiniZinc { EE flatten_arrayaccess(EnvI& env,Ctx ctx, Expression* e, VarDecl* r, VarDecl* b) { CallStackItem _csi(env,e); EE ret; ArrayAccess* aa = e->cast(); KeepAlive aa_ka = aa; Ctx nctx = ctx; nctx.b = +nctx.b; nctx.neg = false; EE eev = flat_exp(env,nctx,aa->v(),NULL,NULL); std::vector ees; start_flatten_arrayaccess: for (unsigned int i=0; iidx().size(); i++) { Expression* tmp = follow_id_to_decl(aa->idx()[i]); if (VarDecl* vd = tmp->dyn_cast()) tmp = vd->id(); if (tmp->type().ispar()) { ArrayLit* al; if (eev.r()->isa()) { al = eev.r()->cast(); } else { Id* id = eev.r()->cast(); if (id->decl()==NULL) { throw InternalError("undefined identifier"); } if (id->decl()->e()==NULL) { throw InternalError("array without initialiser not supported"); } Expression* id_e = follow_id(id); if (id_e->isa()) { al = id_e->cast(); } else { throw InternalError("builtin function returning array not supported"); } } std::vector elems; std::vector idx(aa->idx().size()); std::vector > dims; std::vector newaccess; std::vector nonpar; std::vector stack; for (unsigned int j=0; jidx().size(); j++) { Expression* tmp = follow_id_to_decl(aa->idx()[j]); if (VarDecl* vd = tmp->dyn_cast()) tmp = vd->id(); if (tmp->type().ispar()) { GCLock lock; idx[j] = eval_int(env, tmp).toInt(); } else { idx[j] = al->min(j); stack.push_back(static_cast(nonpar.size())); nonpar.push_back(j); dims.push_back(std::make_pair(al->min(j), al->max(j))); newaccess.push_back(aa->idx()[j]); } } if (stack.empty()) { bool success; KeepAlive ka; { GCLock lock; ka = eval_arrayaccess(env, al, idx, success); if (!success && env.in_maybe_partial==0) { ResultUndefinedError e(env,al->loc(),"array access out of bounds"); } } ees.push_back(EE(NULL,constants().boollit(success))); ees.push_back(EE(NULL,eev.b())); if (aa->type().isbool() && !aa->type().isopt()) { ret.b = bind(env,Ctx(),b,constants().lit_true); ees.push_back(EE(NULL,ka())); ret.r = conj(env,r,ctx,ees); } else { ret.b = conj(env,b,ctx,ees); ret.r = bind(env,ctx,r,ka()); } return ret; } while (!stack.empty()) { int cur = stack.back(); if (cur==nonpar.size()-1) { stack.pop_back(); for (int i = al->min(nonpar[cur]); i <= al->max(nonpar[cur]); i++) { idx[nonpar[cur]] = i; bool success; GCLock lock; Expression* al_idx = eval_arrayaccess(env, al, idx, success); if (!success) { if (env.in_maybe_partial==0) { ResultUndefinedError e(env,al->loc(),"array access out of bounds"); } ees.push_back(EE(NULL,constants().lit_false)); ees.push_back(EE(NULL,eev.b())); if (aa->type().isbool() && !aa->type().isopt()) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = conj(env,r,ctx,ees); } else { ret.b = conj(env,b,ctx,ees); ret.r = bind(env,ctx,r,al_idx); } return ret; } elems.push_back(al_idx); } } else { if (idx[nonpar[cur]].toInt()==al->max(nonpar[cur])) { idx[nonpar[cur]]=al->min(nonpar[cur]); stack.pop_back(); } else { idx[nonpar[cur]]++; for (unsigned int j=cur+1; j elems_e(elems.size()); for (unsigned int i=0; iloc(), elems_e, dims); Type t = al->type(); t.dim(static_cast(dims.size())); newal->type(t); eev.r = newal; ArrayAccess* n_aa = new ArrayAccess(aa->loc(), newal, newaccess); n_aa->type(aa->type()); aa = n_aa; aa_ka = aa; } } } if (aa->idx().size()==1 && aa->idx()[0]->isa()) { ArrayAccess* aa_inner = aa->idx()[0]->cast(); ArrayLit* al; if (eev.r()->isa()) { al = eev.r()->cast(); } else { Id* id = eev.r()->cast(); if (id->decl()==NULL) { throw InternalError("undefined identifier"); } if (id->decl()->e()==NULL) { throw InternalError("array without initialiser not supported"); } al = follow_id(id)->cast(); } if (aa_inner->v()->type().ispar()) { KeepAlive ka_al_inner = flat_cv_exp(env, ctx, aa_inner->v()); ArrayLit* al_inner = ka_al_inner()->cast(); std::vector composed_e(al_inner->size()); for (unsigned int i=0; isize(); i++) { GCLock lock; IntVal inner_idx = eval_int(env, (*al_inner)[i]); if (inner_idx < al->min(0) || inner_idx > al->max(0)) goto flatten_arrayaccess; composed_e[i] = (*al)[static_cast(inner_idx.toInt())-al->min(0)]; } std::vector > dims(al_inner->dims()); for (int i=0; idims(); i++) { dims[i] = std::make_pair(al_inner->min(i), al_inner->max(i)); } { GCLock lock; Expression* newal = new ArrayLit(al->loc(), composed_e, dims); Type t = al->type(); t.dim(static_cast(dims.size())); newal->type(t); eev.r = newal; ArrayAccess* n_aa = new ArrayAccess(aa->loc(), newal, aa_inner->idx()); n_aa->type(aa->type()); aa = n_aa; aa_ka = aa; goto start_flatten_arrayaccess; } } } flatten_arrayaccess: Ctx dimctx = ctx; dimctx.neg = false; for (unsigned int i=0; iidx().size(); i++) { Expression* tmp = follow_id_to_decl(aa->idx()[i]); if (VarDecl* vd = tmp->dyn_cast()) tmp = vd->id(); ees.push_back(flat_exp(env, dimctx, tmp, NULL, NULL)); } ees.push_back(EE(NULL,eev.b())); bool parAccess=true; for (unsigned int i=0; iidx().size(); i++) { if (!ees[i].r()->type().ispar()) { parAccess = false; break; } } if (parAccess) { ArrayLit* al; if (eev.r()->isa()) { al = eev.r()->cast(); } else { Id* id = eev.r()->cast(); if (id->decl()==NULL) { throw InternalError("undefined identifier"); } if (id->decl()->e()==NULL) { throw InternalError("array without initialiser not supported"); } al = follow_id(id)->cast(); } KeepAlive ka; bool success; { GCLock lock; std::vector dims(aa->idx().size()); for (unsigned int i=aa->idx().size(); i--;) dims[i] = eval_int(env,ees[i].r()); ka = eval_arrayaccess(env,al,dims,success); } if (!success && env.in_maybe_partial==0) { ResultUndefinedError e(env,al->loc(),"array access out of bounds"); } ees.push_back(EE(NULL,constants().boollit(success))); if (aa->type().isbool() && !aa->type().isopt()) { ret.b = bind(env,Ctx(),b,constants().lit_true); ees.push_back(EE(NULL,ka())); ret.r = conj(env,r,ctx,ees); } else { ret.b = conj(env,b,ctx,ees); ret.r = bind(env,ctx,r,ka()); } } else { std::vector args(aa->idx().size()+1); for (unsigned int i=aa->idx().size(); i--;) args[i] = ees[i].r(); args[aa->idx().size()] = eev.r(); KeepAlive ka; { GCLock lock; Call* cc = new Call(e->loc().introduce(),constants().ids.element,args); cc->type(aa->type()); FunctionI* fi = env.model->matchFn(env,cc->id(),args,false); if (fi==NULL) { throw FlatteningError(env,cc->loc(), "cannot find matching declaration"); } assert(fi); assert(env.isSubtype(fi->rtype(env,args,false),cc->type(),false)); cc->decl(fi); ka = cc; } Ctx elemctx = ctx; elemctx.neg = false; EE ee = flat_exp(env,elemctx,ka(),NULL,NULL); ees.push_back(ee); if (aa->type().isbool() && !aa->type().isopt()) { ee.b = ee.r; ees.push_back(ee); ret.r = conj(env,r,ctx,ees); ret.b = bind(env,ctx,b,constants().boollit(!ctx.neg)); } else { ret.r = bind(env,ctx,r,ee.r()); ret.b = conj(env,b,ctx,ees); } } return ret; } } libminizinc-2.4.2/lib/flatten/flatten_arraylit.cpp000066400000000000000000000027041360574160400223120ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include namespace MiniZinc { EE flatten_arraylit(EnvI& env,Ctx ctx, Expression* e, VarDecl* r, VarDecl* b) { CallStackItem _csi(env,e); EE ret; ArrayLit* al = e->cast(); if (al->flat()) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,Ctx(),r,al); } else { std::vector elems_ee(al->size()); for (unsigned int i=al->size(); i--;) elems_ee[i] = flat_exp(env,ctx,(*al)[i],NULL,NULL); std::vector elems(elems_ee.size()); for (unsigned int i=static_cast(elems.size()); i--;) elems[i] = elems_ee[i].r(); std::vector > dims(al->dims()); for (unsigned int i=al->dims(); i--;) dims[i] = std::pair(al->min(i), al->max(i)); KeepAlive ka; { GCLock lock; ArrayLit* alr = new ArrayLit(Location().introduce(),elems,dims); alr->type(al->type()); alr->flat(true); ka = alr; } ret.b = conj(env,b,Ctx(),elems_ee); ret.r = bind(env,Ctx(),r,ka()); } return ret; } } libminizinc-2.4.2/lib/flatten/flatten_binop.cpp000066400000000000000000001466171360574160400216060ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include namespace MiniZinc { ASTString opToBuiltin(Expression* op_lhs, Expression* op_rhs, BinOpType bot) { std::string builtin; if (op_rhs->type().isint()) { switch (bot) { case BOT_PLUS: return constants().ids.int_.plus; case BOT_MINUS: return constants().ids.int_.minus; case BOT_MULT: return constants().ids.int_.times; case BOT_POW: return constants().ids.pow; case BOT_IDIV: return constants().ids.int_.div; case BOT_MOD: return constants().ids.int_.mod; case BOT_LE: return constants().ids.int_.lt; case BOT_LQ: return constants().ids.int_.le; case BOT_GR: return constants().ids.int_.gt; case BOT_GQ: return constants().ids.int_.ge; case BOT_EQ: return constants().ids.int_.eq; case BOT_NQ: return constants().ids.int_.ne; default: throw InternalError("not yet implemented"); } } else if (op_rhs->type().isbool()) { if (bot==BOT_EQ || bot==BOT_EQUIV) return constants().ids.bool_eq; builtin = "bool_"; } else if (op_rhs->type().is_set()) { builtin = "set_"; } else if (op_rhs->type().isfloat()) { switch (bot) { case BOT_PLUS: return constants().ids.float_.plus; case BOT_MINUS: return constants().ids.float_.minus; case BOT_MULT: return constants().ids.float_.times; case BOT_POW: return constants().ids.pow; case BOT_DIV: return constants().ids.float_.div; case BOT_MOD: return constants().ids.float_.mod; case BOT_LE: return constants().ids.float_.lt; case BOT_LQ: return constants().ids.float_.le; case BOT_GR: return constants().ids.float_.gt; case BOT_GQ: return constants().ids.float_.ge; case BOT_EQ: return constants().ids.float_.eq; case BOT_NQ: return constants().ids.float_.ne; default: throw InternalError("not yet implemented"); } } else if (op_rhs->type().isopt() && (bot==BOT_EQUIV || bot==BOT_EQ)) { /// TODO: extend to all option type operators switch (op_lhs->type().bt()) { case Type::BT_BOOL: return constants().ids.bool_eq; case Type::BT_FLOAT: return constants().ids.float_.eq; case Type::BT_INT: if (op_lhs->type().st()==Type::ST_PLAIN) return constants().ids.int_.eq; else return constants().ids.set_eq; default: throw InternalError("not yet implemented"); } } else { throw InternalError("Operator not yet implemented"); } switch (bot) { case BOT_PLUS: return builtin+"plus"; case BOT_MINUS: return builtin+"minus"; case BOT_MULT: return builtin+"times"; case BOT_DIV: return builtin+"div"; case BOT_IDIV: return builtin+"div"; case BOT_MOD: return builtin+"mod"; case BOT_LE: return builtin+"lt"; case BOT_LQ: return builtin+"le"; case BOT_GR: return builtin+"gt"; case BOT_GQ: return builtin+"ge"; case BOT_EQ: return builtin+"eq"; case BOT_NQ: return builtin+"ne"; case BOT_IN: return constants().ids.set_in; case BOT_SUBSET: return builtin+"subset"; case BOT_SUPERSET: return builtin+"superset"; case BOT_UNION: return builtin+"union"; case BOT_DIFF: return builtin+"diff"; case BOT_SYMDIFF: return builtin+"symdiff"; case BOT_INTERSECT: return builtin+"intersect"; case BOT_PLUSPLUS: case BOT_DOTDOT: throw InternalError("not yet implemented"); case BOT_EQUIV: return builtin+"eq"; case BOT_IMPL: return builtin+"le"; case BOT_RIMPL: return builtin+"ge"; case BOT_OR: return builtin+"or"; case BOT_AND: return builtin+"and"; case BOT_XOR: return constants().ids.bool_xor; default: assert(false); return ASTString(""); } } bool isReverseMap(BinOp* e) { return e->ann().contains(constants().ann.is_reverse_map); } template void collectLinExps(EnvI& env, typename LinearTraits::Val c, Expression* exp, std::vector::Val>& coeffs, std::vector& vars, typename LinearTraits::Val& constval) { typedef typename LinearTraits::Val Val; struct StackItem { Expression* e; Val c; StackItem(Expression* e0, Val c0) : e(e0), c(c0) {} }; std::vector stack; stack.push_back(StackItem(exp,c)); while (!stack.empty()) { Expression* e = stack.back().e; Val c = stack.back().c; stack.pop_back(); if (e==NULL) continue; if (e->type().ispar()) { constval += c * LinearTraits::eval(env,e); } else if (Lit* l = e->dyn_cast()) { constval += c * l->v(); } else if (BinOp* bo = e->dyn_cast()) { switch (bo->op()) { case BOT_PLUS: stack.push_back(StackItem(bo->lhs(),c)); stack.push_back(StackItem(bo->rhs(),c)); break; case BOT_MINUS: stack.push_back(StackItem(bo->lhs(),c)); stack.push_back(StackItem(bo->rhs(),-c)); break; case BOT_MULT: if (bo->lhs()->type().ispar()) { stack.push_back(StackItem(bo->rhs(),c*LinearTraits::eval(env,bo->lhs()))); } else if (bo->rhs()->type().ispar()) { stack.push_back(StackItem(bo->lhs(),c*LinearTraits::eval(env,bo->rhs()))); } else { coeffs.push_back(c); vars.push_back(e); } break; case BOT_DIV: if (bo->rhs()->isa() && bo->rhs()->cast()->v()==1.0) { stack.push_back(StackItem(bo->lhs(),c)); } else { coeffs.push_back(c); vars.push_back(e); } break; case BOT_IDIV: if (bo->rhs()->isa() && bo->rhs()->cast()->v()==1) { stack.push_back(StackItem(bo->lhs(),c)); } else { coeffs.push_back(c); vars.push_back(e); } break; default: coeffs.push_back(c); vars.push_back(e); break; } // } else if (Call* call = e->dyn_cast()) { // /// TODO! Handle sum, lin_exp (maybe not that important?) } else { coeffs.push_back(c); vars.push_back(e); } } } template KeepAlive mklinexp(EnvI& env, typename LinearTraits::Val c0, typename LinearTraits::Val c1, Expression* e0, Expression* e1) { typedef typename LinearTraits::Val Val; GCLock lock; std::vector coeffs; std::vector vars; Val constval = 0; collectLinExps(env, c0, e0, coeffs, vars, constval); collectLinExps(env, c1, e1, coeffs, vars, constval); simplify_lin(coeffs, vars, constval); KeepAlive ka; if (coeffs.size()==0) { ka = LinearTraits::newLit(constval); } else if (coeffs.size()==1 && coeffs[0]==1 && constval==0) { ka = vars[0]; } else { std::vector coeffs_e(coeffs.size()); for (unsigned int i=static_cast(coeffs.size()); i--;) { if (!LinearTraits::finite(coeffs[i])) { throw FlatteningError(env,e0->loc(), "unbounded coefficient in linear expression." " Make sure variables involved in non-linear/logical expressions have finite bounds" " in their definition or via constraints" ); } coeffs_e[i] = LinearTraits::newLit(coeffs[i]); } std::vector vars_e(vars.size()); for (unsigned int i=static_cast(vars.size()); i--;) vars_e[i] = vars[i](); std::vector args(3); args[0]=new ArrayLit(e0->loc(),coeffs_e); Type t = coeffs_e[0]->type(); t.dim(1); args[0]->type(t); args[1]=new ArrayLit(e0->loc(),vars_e); Type tt = vars_e[0]->type(); tt.dim(1); args[1]->type(tt); args[2] = LinearTraits::newLit(constval); Call* c = new Call(e0->loc().introduce(),constants().ids.lin_exp,args); addPathAnnotation(env, c); tt = args[1]->type(); tt.dim(0); c->decl(env.model->matchFn(env, c, false)); if (c->decl()==NULL) { throw FlatteningError(env,c->loc(), "cannot find matching declaration"); } c->type(c->decl()->rtype(env, args, false)); ka = c; } assert(ka()); return ka; } Call* aggregateAndOrOps(EnvI& env, BinOp* bo, bool negateArgs, BinOpType bot) { assert(bot == BOT_AND || bot == BOT_OR); BinOpType negbot = (bot == BOT_AND ? BOT_OR : BOT_AND); typedef std::pair arg_literal; std::vector bo_args(2); bo_args[0] = arg_literal(bo->lhs(), !negateArgs); bo_args[1] = arg_literal(bo->rhs(), !negateArgs); std::vector output_pos; std::vector output_neg; unsigned int processed = 0; while (processed < bo_args.size()) { BinOp* bo_arg = bo_args[processed].first->dyn_cast(); UnOp* uo_arg = bo_args[processed].first->dyn_cast(); bool positive = bo_args[processed].second; if (bo_arg && positive && bo_arg->op() == bot) { bo_args[processed].first = bo_arg->lhs(); bo_args.push_back(arg_literal(bo_arg->rhs(),true)); } else if (bo_arg && !positive && bo_arg->op() == negbot) { bo_args[processed].first = bo_arg->lhs(); bo_args.push_back(arg_literal(bo_arg->rhs(),false)); } else if (uo_arg && !positive && uo_arg->op() == UOT_NOT) { bo_args[processed].first = uo_arg->e(); bo_args[processed].second = true; } else if (bot==BOT_OR && uo_arg && positive && uo_arg->op() == UOT_NOT) { output_neg.push_back(uo_arg->e()); processed++; } else { if (positive) { output_pos.push_back(bo_args[processed].first); } else { output_neg.push_back(bo_args[processed].first); } processed++; } } Call* c; std::vector c_args(1); if (bot == BOT_AND) { for (unsigned int i=0; iloc(),UOT_NOT,output_neg[i]); neg_arg->type(output_neg[i]->type()); output_pos.push_back(neg_arg); } ArrayLit* al = new ArrayLit(bo->loc().introduce(), output_pos); Type al_t = bo->type(); al_t.dim(1); al->type(al_t); env.annotateFromCallStack(al); c_args[0] = al; c = new Call(bo->loc().introduce(), bot==BOT_AND ? constants().ids.forall : constants().ids.exists, c_args); } else { ArrayLit* al_pos = new ArrayLit(bo->loc().introduce(), output_pos); Type al_t = bo->type(); al_t.dim(1); al_pos->type(al_t); env.annotateFromCallStack(al_pos); c_args[0] = al_pos; if (output_neg.size() > 0) { ArrayLit* al_neg = new ArrayLit(bo->loc().introduce(), output_neg); al_neg->type(al_t); env.annotateFromCallStack(al_neg); c_args.push_back(al_neg); } c = new Call(bo->loc().introduce(), output_neg.empty() ? constants().ids.exists : constants().ids.clause, c_args); } c->decl(env.model->matchFn(env, c, false)); assert(c->decl()); Type t = c->decl()->rtype(env, c_args, false); t.cv(bo->type().cv()); c->type(t); return c; } /// Return a lin_exp or id if \a e is a lin_exp or id template Expression* get_linexp(Expression* e) { for (;;) { if (e && e->eid()==Expression::E_ID && e != constants().absent) { if (e->cast()->decl()->e()) { e = e->cast()->decl()->e(); } else { break; } } else { break; } } if (e && (e->isa() || e->isa() || (e->isa() && e->cast()->id() == constants().ids.lin_exp))) return e; return NULL; } template void flatten_linexp_binop(EnvI& env, Ctx ctx, VarDecl* r, VarDecl* b, EE& ret, Expression* le0, Expression* le1, BinOpType& bot, bool doubleNeg, std::vector& ees, std::vector& args, ASTString& callid) { typedef typename LinearTraits::Val Val; std::vector coeffv; std::vector alv; Val d = 0; Expression* le[2] = {le0,le1}; Id* assignTo = NULL; if (bot==BOT_EQ && ctx.b == C_ROOT) { if (le0->isa()) { assignTo = le0->cast(); } else if (le1->isa()) { assignTo = le1->cast(); } } for (unsigned int i=0; i<2; i++) { Val sign = (i==0 ? 1 : -1); if (Lit* l = le[i]->dyn_cast()) { try { d += sign*l->v(); } catch (ArithmeticError& e) { throw EvalError(env,l->loc(),e.msg()); } } else if (le[i]->isa()) { coeffv.push_back(sign); alv.push_back(le[i]); } else if (Call* sc = le[i]->dyn_cast()) { GCLock lock; ArrayLit* sc_coeff = eval_array_lit(env,sc->arg(0)); ArrayLit* sc_al = eval_array_lit(env,sc->arg(1)); try { d += sign*LinearTraits::eval(env,sc->arg(2)); for (unsigned int j=0; jsize(); j++) { coeffv.push_back(sign*LinearTraits::eval(env,(*sc_coeff)[j])); alv.push_back((*sc_al)[j]); } } catch (ArithmeticError& e) { throw EvalError(env,sc->loc(),e.msg()); } } else { throw EvalError(env, le[i]->loc(), "Internal error, unexpected expression inside linear expression"); } } simplify_lin(coeffv,alv,d); if (coeffv.size()==0) { bool result; switch (bot) { case BOT_LE: result = (0<-d); break; case BOT_LQ: result = (0<=-d); break; case BOT_GR: result = (0>-d); break; case BOT_GQ: result = (0>=-d); break; case BOT_EQ: result = (0==-d); break; case BOT_NQ: result = (0!=-d); break; default: assert(false); break; } if (doubleNeg) result = !result; ees[2].b = constants().boollit(result); ret.r = conj(env,r,ctx,ees); return; } else if (coeffv.size()==1 && std::abs(coeffv[0])==1) { if (coeffv[0]==-1) { switch (bot) { case BOT_LE: bot = BOT_GR; break; case BOT_LQ: bot = BOT_GQ; break; case BOT_GR: bot = BOT_LE; break; case BOT_GQ: bot = BOT_LQ; break; default: break; } } else { d = -d; } typename LinearTraits::Bounds ib = LinearTraits::compute_bounds(env,alv[0]()); if (ib.valid) { bool failed = false; bool subsumed = false; switch (bot) { case BOT_LE: subsumed = ib.u < d; failed = ib.l >= d; break; case BOT_LQ: subsumed = ib.u <= d; failed = ib.l > d; break; case BOT_GR: subsumed = ib.l > d; failed = ib.u <= d; break; case BOT_GQ: subsumed = ib.l >= d; failed = ib.u < d; break; case BOT_EQ: subsumed = ib.l==d && ib.u==d; failed = ib.u < d || ib.l > d; break; case BOT_NQ: subsumed = ib.u < d || ib.l > d; failed = ib.l==d && ib.u==d; break; default: break; } if (doubleNeg) { std::swap(subsumed, failed); } if (subsumed) { ees[2].b = constants().lit_true; ret.r = conj(env,r,ctx,ees); return; } else if (failed) { ees[2].b = constants().lit_false; ret.r = conj(env,r,ctx,ees); return; } } if (ctx.b == C_ROOT && alv[0]()->isa() && bot==BOT_EQ) { GCLock lock; VarDecl* vd = alv[0]()->cast()->decl(); if (vd->ti()->domain()) { typename LinearTraits::Domain domain = LinearTraits::eval_domain(env,vd->ti()->domain()); if (LinearTraits::domain_contains(domain,d)) { if (!LinearTraits::domain_equals(domain,d)) { //vd->ti()->setComputedDomain(false); //vd->ti()->domain(LinearTraits::new_domain(d)); setComputedDomain(env, vd, LinearTraits::new_domain(d), false); } ret.r = bind(env,ctx,r,constants().lit_true); } else { ret.r = bind(env,ctx,r,constants().lit_false); } } else { //vd->ti()->setComputedDomain(false); //vd->ti()->domain(LinearTraits::new_domain(d)); setComputedDomain(env, vd, LinearTraits::new_domain(d), false); ret.r = bind(env,ctx,r,constants().lit_true); } } else { GCLock lock; Expression* e0; Expression* e1; BinOpType old_bot = bot; Val old_d = d; switch (bot) { case BOT_LE: e0 = alv[0](); if (e0->type().isint()) { d--; bot = BOT_LQ; } e1 = LinearTraits::newLit(d); break; case BOT_GR: e1 = alv[0](); if (e1->type().isint()) { d++; bot = BOT_LQ; } else { bot = BOT_LE; } e0 = LinearTraits::newLit(d); break; case BOT_GQ: e0 = LinearTraits::newLit(d); e1 = alv[0](); bot = BOT_LQ; break; default: e0 = alv[0](); e1 = LinearTraits::newLit(d); } if (ctx.b == C_ROOT && alv[0]()->isa() && alv[0]()->cast()->decl()->ti()->domain()) { VarDecl* vd = alv[0]()->cast()->decl(); typename LinearTraits::Domain domain = LinearTraits::eval_domain(env,vd->ti()->domain()); typename LinearTraits::Domain ndomain = LinearTraits::limit_domain(old_bot,domain,old_d); if (domain && ndomain) { if (LinearTraits::domain_empty(ndomain)) { ret.r = bind(env,ctx,r,constants().lit_false); return; } else if (!LinearTraits::domain_equals(domain,ndomain)) { ret.r = bind(env,ctx,r,constants().lit_true); //vd->ti()->setComputedDomain(false); //vd->ti()->domain(LinearTraits::new_domain(ndomain)); setComputedDomain(env, vd, LinearTraits::new_domain(ndomain), false); if (r==constants().var_true) { BinOp* bo = new BinOp(Location().introduce(), e0, bot, e1); bo->type(Type::varbool()); std::vector boargs(2); boargs[0] = e0; boargs[1] = e1; Call* c = new Call(Location(), opToBuiltin(e0, e1, bot), boargs); c->type(Type::varbool()); c->decl(env.model->matchFn(env, c, false)); EnvI::CSEMap::iterator it = env.cse_map_find(c); if (it != env.cse_map_end()) { if (Id* ident = it->second.r()->template dyn_cast()) { bind(env, Ctx(), ident->decl(), constants().lit_true); it->second.r = constants().lit_true; } if (Id* ident = it->second.b()->template dyn_cast()) { bind(env, Ctx(), ident->decl(), constants().lit_true); it->second.b = constants().lit_true; } } } } return; } } args.push_back(e0); args.push_back(e1); } } else if (bot==BOT_EQ && coeffv.size()==2 && coeffv[0]==-coeffv[1] && d==0) { Id* id0 = alv[0]()->cast(); Id* id1 = alv[1]()->cast(); if (ctx.b == C_ROOT && r==constants().var_true && (id0->decl()->e()==NULL || id1->decl()->e()==NULL)) { if (id0->decl()->e()) (void) bind(env,ctx,id1->decl(),id0); else (void) bind(env,ctx,id0->decl(),id1); } else { callid = LinearTraits::id_eq(); args.push_back(alv[0]()); args.push_back(alv[1]()); } } else { GCLock lock; if (assignTo != NULL) { Val resultCoeff = 0; typename LinearTraits::Bounds bounds(d,d,true); for (unsigned int i=static_cast(coeffv.size()); i--;) { if (alv[i]()==assignTo) { resultCoeff = coeffv[i]; continue; } typename LinearTraits::Bounds b = LinearTraits::compute_bounds(env,alv[i]()); if (b.valid && LinearTraits::finite(b)) { if (coeffv[i] > 0) { bounds.l += coeffv[i]*b.l; bounds.u += coeffv[i]*b.u; } else { bounds.l += coeffv[i]*b.u; bounds.u += coeffv[i]*b.l; } } else { bounds.valid = false; break; } } if (bounds.valid && resultCoeff!=0) { if (resultCoeff < 0) { bounds.l = LinearTraits::floor_div(bounds.l,-resultCoeff); bounds.u = LinearTraits::ceil_div(bounds.u,-resultCoeff); } else { Val bl = bounds.l; bounds.l = LinearTraits::ceil_div(bounds.u,-resultCoeff); bounds.u = LinearTraits::floor_div(bl,-resultCoeff); } VarDecl* vd = assignTo->decl(); if (vd->ti()->domain()) { typename LinearTraits::Domain domain = LinearTraits::eval_domain(env,vd->ti()->domain()); if (LinearTraits::domain_intersects(domain,bounds.l,bounds.u)) { typename LinearTraits::Domain new_domain = LinearTraits::intersect_domain(domain,bounds.l,bounds.u); if (!LinearTraits::domain_equals(domain,new_domain)) { //vd->ti()->setComputedDomain(false); //vd->ti()->domain(LinearTraits::new_domain(new_domain)); setComputedDomain(env, vd, LinearTraits::new_domain(new_domain), false); } } else { ret.r = bind(env,ctx,r,constants().lit_false); } } else { //vd->ti()->setComputedDomain(true); //vd->ti()->domain(LinearTraits::new_domain(bounds.l,bounds.u)); setComputedDomain(env, vd, LinearTraits::new_domain(bounds.l, bounds.u), true); } } } int coeff_sign; LinearTraits::constructLinBuiltin(bot,callid,coeff_sign,d); std::vector coeff_ev(coeffv.size()); for (unsigned int i=static_cast(coeff_ev.size()); i--;) coeff_ev[i] = LinearTraits::newLit(coeff_sign*coeffv[i]); ArrayLit* ncoeff = new ArrayLit(Location().introduce(),coeff_ev); Type t = coeff_ev[0]->type(); t.dim(1); ncoeff->type(t); args.push_back(ncoeff); std::vector alv_e(alv.size()); Type tt = alv[0]()->type(); tt.dim(1); for (unsigned int i=static_cast(alv.size()); i--;) { if (alv[i]()->type().isvar()) tt.ti(Type::TI_VAR); alv_e[i] = alv[i](); } ArrayLit* nal = new ArrayLit(Location().introduce(),alv_e); nal->type(tt); args.push_back(nal); Lit* il = LinearTraits::newLit(-d); args.push_back(il); } } EE flatten_binop(EnvI& env,Ctx ctx, Expression* e, VarDecl* r, VarDecl* b) { CallStackItem _csi(env,e); EE ret; BinOp* bo = e->cast(); if (isReverseMap(bo)) { CallArgItem cai(env); Id* id = bo->lhs()->dyn_cast(); if (id==NULL) throw EvalError(env, bo->lhs()->loc(), "Reverse mappers are only defined for identifiers"); if (bo->op() != BOT_EQ && bo->op() != BOT_EQUIV) throw EvalError(env, bo->loc(), "Reverse mappers have to use `=` as the operator"); Call* c = bo->rhs()->dyn_cast(); if (c==NULL) throw EvalError(env, bo->rhs()->loc(), "Reverse mappers require call on right hand side"); std::vector args(c->n_args()); for (unsigned int i=0; in_args(); i++) { Id* idi = c->arg(i)->dyn_cast(); if (idi==NULL) throw EvalError(env, c->arg(i)->loc(), "Reverse mapper calls require identifiers as arguments"); EE ee = flat_exp(env, Ctx(), idi, NULL, constants().var_true); args[i] = ee.r(); } EE ee = flat_exp(env, Ctx(), id, NULL, constants().var_true); GCLock lock; Call* revMap = new Call(Location().introduce(),c->id(),args); args.push_back(ee.r()); Call* keepAlive = new Call(Location().introduce(),constants().var_redef->id(),args); keepAlive->type(Type::varbool()); keepAlive->decl(constants().var_redef); ret = flat_exp(env, Ctx(), keepAlive, constants().var_true, constants().var_true); if (ee.r()->isa()) { env.reverseMappers.insert(ee.r()->cast(),revMap); } return ret; } if ( (bo->op()==BOT_EQ || bo->op()==BOT_EQUIV) && (bo->lhs()==constants().absent || bo->rhs()==constants().absent) ) { GCLock lock; std::vector args(1); args[0] = bo->lhs()==constants().absent ? bo->rhs() : bo->lhs(); if (args[0] != constants().absent) { Call* cr = new Call(bo->loc().introduce(),"absent",args); cr->decl(env.model->matchFn(env, cr, false)); cr->type(cr->decl()->rtype(env, args, false)); ret = flat_exp(env, ctx, cr, r, b); } else { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,ctx,r,constants().lit_true); } return ret; } Ctx ctx0 = ctx; ctx0.neg = false; Ctx ctx1 = ctx; ctx1.neg = false; BinOpType bot = bo->op(); if (bo->lhs()->type().isbool()) { switch (bot) { case BOT_EQ: bot = BOT_EQUIV; break; case BOT_NQ: bot = BOT_XOR; break; case BOT_LQ: bot = BOT_IMPL; break; case BOT_GQ: bot = BOT_RIMPL; break; default: break; } } bool negArgs = false; bool doubleNeg = false; if (ctx.neg) { switch (bot) { case BOT_AND: ctx.b = -ctx.b; ctx.neg = false; negArgs = true; bot = BOT_OR; break; case BOT_OR: ctx.b = -ctx.b; ctx.neg = false; negArgs = true; bot = BOT_AND; break; default: break; } } Expression* boe0 = bo->lhs(); Expression* boe1 = bo->rhs(); bool isBuiltin = bo->decl()==NULL || bo->decl()->e()==NULL; switch (bot) { case BOT_PLUS: if (isBuiltin) { KeepAlive ka; if (boe0->type().isint()) { ka = mklinexp(env,1,1,boe0,boe1); } else { ka = mklinexp(env,1.0,1.0,boe0,boe1); } ret = flat_exp(env,ctx,ka(),r,b); break; } case BOT_MINUS: if (isBuiltin) { KeepAlive ka; if (boe0->type().isint()) { ka = mklinexp(env,1,-1,boe0,boe1); } else { ka = mklinexp(env,1.0,-1.0,boe0,boe1); } ret = flat_exp(env,ctx,ka(),r,b); break; } case BOT_MULT: case BOT_IDIV: case BOT_MOD: case BOT_POW: case BOT_DIV: case BOT_UNION: case BOT_DIFF: case BOT_SYMDIFF: case BOT_INTERSECT: case BOT_DOTDOT: { assert(!ctx0.neg); assert(!ctx1.neg); EE e0 = flat_exp(env,ctx0,boe0,NULL,b); EE e1 = flat_exp(env,ctx1,boe1,NULL,b); if (e0.r()->type().ispar() && e1.r()->type().ispar()) { GCLock lock; BinOp* parbo = new BinOp(bo->loc(),e0.r(),bo->op(),e1.r()); Type tt = bo->type(); tt.ti(Type::TI_PAR); parbo->type(tt); try { Expression* res = eval_par(env,parbo); assert(!res->type().isunknown()); ret.r = bind(env,ctx,r,res); std::vector ees(2); ees[0].b = e0.b; ees[1].b = e1.b; ret.b = conj(env,b,Ctx(),ees); } catch (ResultUndefinedError&) { ret.r = createDummyValue(env, e->type()); ret.b = bind(env,Ctx(),b,constants().lit_false); } break; } if (isBuiltin && bot==BOT_MULT) { Expression* e0r = e0.r(); Expression* e1r = e1.r(); if (e0r->type().ispar()) std::swap(e0r,e1r); if (e1r->type().ispar() && e1r->type().isint()) { IntVal coeff = eval_int(env,e1r); KeepAlive ka = mklinexp(env,coeff,0,e0r,NULL); ret = flat_exp(env,ctx,ka(),r,b); break; } else if (e1r->type().ispar() && e1r->type().isfloat()) { FloatVal coeff = eval_float(env,e1r); KeepAlive ka = mklinexp(env,coeff,0.0,e0r,NULL); ret = flat_exp(env,ctx,ka(),r,b); break; } } else if (isBuiltin && (bot==BOT_DIV || bot==BOT_IDIV)) { Expression* e0r = e0.r(); Expression* e1r = e1.r(); if (e1r->type().ispar() && e1r->type().isint()) { IntVal coeff = eval_int(env,e1r); if (coeff==1) { ret = flat_exp(env,ctx,e0r,r,b); break; } } else if (e1r->type().ispar() && e1r->type().isfloat()) { FloatVal coeff = eval_float(env,e1r); if (coeff==1.0) { ret = flat_exp(env,ctx,e0r,r,b); break; } else { KeepAlive ka = mklinexp(env,1.0/coeff,0.0,e0r,NULL); ret = flat_exp(env,ctx,ka(),r,b); break; } } } GC::lock(); std::vector args(2); args[0] = e0.r(); args[1] = e1.r(); Call* cc; if (bo->decl()) { cc = new Call(bo->loc().introduce(),bo->opToString(),args); } else { cc = new Call(bo->loc().introduce(),opToBuiltin(args[0],args[1],bot),args); } cc->type(bo->type()); EnvI::CSEMap::iterator cit; if ( (cit = env.cse_map_find(cc)) != env.cse_map_end()) { ret.b = bind(env,Ctx(),b,env.ignorePartial ? constants().lit_true : cit->second.b()); ret.r = bind(env,ctx,r,cit->second.r()); } else { if (FunctionI* fi = env.model->matchFn(env,cc->id(),args,false)) { assert(cc->type() == fi->rtype(env,args,false)); cc->decl(fi); cc->type(cc->decl()->rtype(env,args,false)); KeepAlive ka(cc); GC::unlock(); EE ee = flat_exp(env,ctx,cc,r,NULL); GC::lock(); ret.r = ee.r; std::vector ees(3); ees[0].b = e0.b; ees[1].b = e1.b; ees[2].b = ee.b; ret.b = conj(env,b,Ctx(),ees); } else { addPathAnnotation(env, cc); ret.r = bind(env,ctx,r,cc); std::vector ees(2); ees[0].b = e0.b; ees[1].b = e1.b; ret.b = conj(env,b,Ctx(),ees); if (!ctx.neg) env.cse_map_insert(cc,ret); } } } GC::unlock(); break; case BOT_AND: { if (r==constants().var_true) { Ctx nctx; nctx.neg = negArgs; nctx.b = negArgs ? C_NEG : C_ROOT; std::vector todo; todo.push_back(boe1); todo.push_back(boe0); while (!todo.empty()) { Expression* e_todo = todo.back(); todo.pop_back(); BinOp* e_bo = e_todo->dyn_cast(); if (e_bo && e_bo->op() == (negArgs ? BOT_OR : BOT_AND)) { todo.push_back(e_bo->rhs()); todo.push_back(e_bo->lhs()); } else { (void) flat_exp(env,nctx,e_todo,constants().var_true,constants().var_true); } } ret.r = bind(env,ctx,r,constants().lit_true); break; } else { GC::lock(); Call* c = aggregateAndOrOps(env, bo, negArgs, bot); KeepAlive ka(c); GC::unlock(); ret = flat_exp(env,ctx,c,r,b); if (Id* id = ret.r()->dyn_cast()) { addCtxAnn(id->decl(), ctx.b); } } break; } case BOT_OR: { GC::lock(); Call* c = aggregateAndOrOps(env, bo, negArgs, bot); KeepAlive ka(c); GC::unlock(); ret = flat_exp(env,ctx,c,r,b); if (Id* id = ret.r()->dyn_cast()) { addCtxAnn(id->decl(), ctx.b); } } break; case BOT_RIMPL: { std::swap(boe0,boe1); } // fall through case BOT_IMPL: { if (ctx.b==C_ROOT && r==constants().var_true && boe0->type().ispar()) { bool b; { GCLock lock; b = eval_bool(env,boe0); } if (b) { Ctx nctx = ctx; nctx.neg = negArgs; nctx.b = negArgs ? C_NEG : C_ROOT; ret = flat_exp(env,nctx,boe1,constants().var_true,constants().var_true); } else { Ctx nctx = ctx; nctx.neg = negArgs; nctx.b = negArgs ? C_NEG : C_ROOT; ret = flat_exp(env,nctx,constants().lit_true,constants().var_true,constants().var_true); } break; } if (ctx.b==C_ROOT && r==constants().var_true && boe1->type().ispar()) { bool b; { GCLock lock; b = eval_bool(env,boe1); } if (b) { Ctx nctx = ctx; nctx.neg = negArgs; nctx.b = negArgs ? C_NEG : C_ROOT; ret = flat_exp(env,nctx,constants().lit_true,constants().var_true,constants().var_true); break; } else { Ctx nctx = ctx; nctx.neg = !negArgs; nctx.b = !negArgs ? C_NEG : C_ROOT; ret = flat_exp(env,nctx,boe0,constants().var_true,constants().var_true); break; } } GC::lock(); std::vector args; ASTString id; if (ctx.neg) { std::vector bo_args(2); bo_args[0] = boe0; bo_args[1] = new UnOp(bo->loc(),UOT_NOT,boe1); bo_args[1]->type(boe1->type()); id = constants().ids.forall; args.push_back(new ArrayLit(bo->loc(),bo_args)); args[0]->type(Type::varbool(1)); } else { std::vector clause_pos(1); clause_pos[0] = boe1; std::vector clause_neg(1); clause_neg[0] = boe0; args.push_back(new ArrayLit(boe1->loc().introduce(), clause_pos)); Type t0 = boe1->type(); t0.dim(1); args[0]->type(t0); args.push_back(new ArrayLit(boe0->loc().introduce(), clause_neg)); Type t1 = boe0->type(); t1.dim(1); args[1]->type(t1); id = constants().ids.clause; } ctx.neg = false; Call* c = new Call(bo->loc().introduce(),id,args); c->decl(env.model->matchFn(env,c,false)); if (c->decl()==NULL) { throw FlatteningError(env,c->loc(), "cannot find matching declaration"); } c->type(c->decl()->rtype(env,args,false)); KeepAlive ka(c); GC::unlock(); ret = flat_exp(env,ctx,c,r,b); if (Id* id = ret.r()->dyn_cast()) { addCtxAnn(id->decl(),ctx.b); } } break; case BOT_EQUIV: if (ctx.neg) { ctx.neg = false; ctx.b = -ctx.b; bot = BOT_XOR; ctx0.b = ctx1.b = C_MIX; goto flatten_bool_op; } else { if (!boe1->type().isopt() && istrue(env, boe0)) { return flat_exp(env, ctx, boe1, r, b); } if (!boe0->type().isopt() && istrue(env, boe1)) { return flat_exp(env, ctx, boe0, r, b); } if (r && r==constants().var_true) { if (boe1->type().ispar() || boe1->isa()) std::swap(boe0,boe1); if (istrue(env,boe0)) { return flat_exp(env,ctx1,boe1,r,b); } else if (isfalse(env,boe0)) { ctx1.neg = true; ctx1.b = -ctx1.b; return flat_exp(env,ctx1,boe1,r,b); } else { ctx0.b = C_MIX; EE e0 = flat_exp(env,ctx0,boe0,NULL,NULL); if (istrue(env,e0.r())) { return flat_exp(env,ctx1,boe1,r,b); } else if (isfalse(env,e0.r())) { ctx1.neg = true; ctx1.b = -ctx1.b; return flat_exp(env,ctx1,boe1,r,b); } else { Id* id = e0.r()->cast(); ctx1.b = C_MIX; (void) flat_exp(env,ctx1,boe1,id->decl(),constants().var_true); addCtxAnn(id->decl(), ctx1.b); ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,Ctx(),r,constants().lit_true); } } break; } else { ctx0.b = ctx1.b = C_MIX; goto flatten_bool_op; } } case BOT_XOR: if (ctx.neg) { ctx.neg = false; ctx.b = -ctx.b; bot = BOT_EQUIV; } ctx0.b = ctx1.b = C_MIX; goto flatten_bool_op; case BOT_LE: if (ctx.neg) { doubleNeg = true; bot = BOT_GQ; if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = +ctx0.b; ctx1.b = -ctx1.b; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = +ctx0.b; ctx1.i = -ctx1.b; } } else { if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = -ctx0.b; ctx1.b = +ctx1.b; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = -ctx0.b; ctx1.i = +ctx1.b; } } goto flatten_bool_op; case BOT_LQ: if (ctx.neg) { doubleNeg = true; bot = BOT_GR; if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = +ctx0.b; ctx1.b = -ctx1.b; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = +ctx0.b; ctx1.i = -ctx1.b; } } else { if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = -ctx0.b; ctx1.b = +ctx1.b; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = -ctx0.b; ctx1.i = +ctx1.b; } } goto flatten_bool_op; case BOT_GR: if (ctx.neg) { doubleNeg = true; bot = BOT_LQ; if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = -ctx0.b; ctx1.b = +ctx1.b; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = -ctx0.b; ctx1.i = +ctx1.b; } } else { if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = +ctx0.b; ctx1.b = -ctx1.b; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = +ctx0.b; ctx1.i = -ctx1.b; } } goto flatten_bool_op; case BOT_GQ: if (ctx.neg) { doubleNeg = true; bot = BOT_LE; if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = -ctx0.b; ctx1.b = +ctx1.b; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = -ctx0.b; ctx1.i = +ctx1.b; } } else { if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = +ctx0.b; ctx1.b = -ctx1.b; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = +ctx0.b; ctx1.i = -ctx1.b; } } goto flatten_bool_op; case BOT_EQ: if (ctx.neg) { doubleNeg = true; bot = BOT_NQ; } if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = ctx1.b = C_MIX; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = ctx1.i = C_MIX; } goto flatten_bool_op; case BOT_NQ: if (ctx.neg) { doubleNeg = true; bot = BOT_EQ; } if (boe0->type().bt()==Type::BT_BOOL) { ctx0.b = ctx1.b = C_MIX; } else if (boe0->type().bt()==Type::BT_INT) { ctx0.i = ctx1.i = C_MIX; } goto flatten_bool_op; case BOT_IN: case BOT_SUBSET: case BOT_SUPERSET: ctx0.i = ctx1.i = C_MIX; flatten_bool_op: { bool inRootCtx = (ctx0.b==ctx1.b && ctx0.b==C_ROOT && b==constants().var_true); EE e0 = flat_exp(env,ctx0,boe0,NULL,inRootCtx ? b : NULL); EE e1 = flat_exp(env,ctx1,boe1,NULL,inRootCtx ? b : NULL); ret.b = bind(env,Ctx(),b,constants().lit_true); std::vector ees(3); ees[0].b = e0.b; ees[1].b = e1.b; if (isfalse(env, e0.b()) || isfalse(env, e1.b())) { ees.resize(2); ret.r = conj(env,r,ctx,ees); break; } if (e0.r()->type().ispar() && e1.r()->type().ispar()) { GCLock lock; BinOp* bo_par = new BinOp(e->loc(),e0.r(),bot,e1.r()); std::vector args({e0.r(),e1.r()}); bo_par->decl(env.model->matchFn(env,bo_par->opToString(),args,false)); if (bo_par->decl()==NULL) { throw FlatteningError(env,bo_par->loc(), "cannot find matching declaration"); } bo_par->type(Type::parbool()); bool bo_val = eval_bool(env,bo_par); if (doubleNeg) bo_val = !bo_val; ees[2].b = constants().boollit(bo_val); ret.r = conj(env,r,ctx,ees); break; } if (e0.r()->type().bt()==Type::BT_INT && e1.r()->type().ispar() && e0.r()->isa() && (bot==BOT_IN || bot==BOT_SUBSET)) { VarDecl* vd = e0.r()->cast()->decl(); Id* ident = vd->id(); if (ctx.b==C_ROOT && r==constants().var_true) { if (vd->ti()->domain()==NULL) { vd->ti()->domain(e1.r()); } else { GCLock lock; IntSetVal* newdom = eval_intset(env,e1.r()); while (ident != NULL) { bool changeDom = false; if (ident->decl()->ti()->domain()) { IntSetVal* domain = eval_intset(env,ident->decl()->ti()->domain()); IntSetRanges dr(domain); IntSetRanges ibr(newdom); Ranges::Inter i(dr,ibr); IntSetVal* newibv = IntSetVal::ai(i); if (domain->card() != newibv->card()) { newdom = newibv; changeDom = true; } } else { changeDom = true; } if (ident->type().st()==Type::ST_PLAIN && newdom->size()==0) { env.fail(); } else if (changeDom) { //ident->decl()->ti()->setComputedDomain(false); //ident->decl()->ti()->domain(new SetLit(Location().introduce(),newdom)); setComputedDomain(env, ident->decl(), new SetLit(Location().introduce(), newdom), false); if (ident->decl()->e()==NULL && newdom->min()==newdom->max() && !vd->type().is_set()) { ident->decl()->e(IntLit::a(newdom->min())); } } ident = ident->decl()->e() ? ident->decl()->e()->dyn_cast() : NULL; } } ret.r = bind(env,ctx,r,constants().lit_true); break; } else if (vd->ti()->domain()!=NULL) { // check if current domain is already subsumed or falsified by this constraint GCLock lock; IntSetVal* check_dom = eval_intset(env,e1.r()); IntSetVal* domain = eval_intset(env,ident->decl()->ti()->domain()); { IntSetRanges cdr(check_dom); IntSetRanges dr(domain); if (Ranges::subset(dr,cdr)) { // the constraint is subsumed ret.r = bind(env,ctx,r,constants().lit_true); break; } } if (vd->type().st()==Type::ST_PLAIN) { // only for var int (for var set of int, subset can never fail because of the domain) IntSetRanges cdr(check_dom); IntSetRanges dr(domain); if (Ranges::disjoint(cdr, dr)) { // the constraint is false ret.r = bind(env,ctx,r,constants().lit_false); break; } } } } std::vector args; ASTString callid; Expression* le0 = NULL; Expression* le1 = NULL; if (boe0->type().isint() && !boe0->type().isopt() && bot != BOT_IN) { le0 = get_linexp(e0.r()); } else if (boe0->type().isfloat() && !boe0->type().isopt() && bot != BOT_IN) { le0 = get_linexp(e0.r()); } if (le0) { if (boe0->type().isint() && boe1->type().isint() && !boe1->type().isopt()) { le1 = get_linexp(e1.r()); } else if (boe0->type().isfloat() && boe1->type().isfloat() && !boe1->type().isopt()) { le1 = get_linexp(e1.r()); } } if (le1) { if (boe0->type().isint()) { flatten_linexp_binop(env,ctx,r,b,ret,le0,le1,bot,doubleNeg,ees,args,callid); } else { flatten_linexp_binop(env,ctx,r,b,ret,le0,le1,bot,doubleNeg,ees,args,callid); } } else { if (bo->decl()==NULL) { switch (bot) { case BOT_GR: std::swap(e0,e1); bot = BOT_LE; break; case BOT_GQ: std::swap(e0,e1); bot = BOT_LQ; break; default: break; } } args.push_back(e0.r); args.push_back(e1.r); } if (args.size() > 0) { GC::lock(); if (callid=="") { assert(args.size()==2); if (bo->decl()) { callid = bo->decl()->id(); } else { callid = opToBuiltin(args[0](),args[1](),bot); } } std::vector args_e(args.size()); for (unsigned int i=static_cast(args.size()); i--;) args_e[i] = args[i](); Call* cc = new Call(e->loc().introduce(),callid,args_e); cc->decl(env.model->matchFn(env,cc->id(),args_e,false)); if (cc->decl()==NULL) { throw FlatteningError(env,cc->loc(), "cannot find matching declaration"); } cc->type(cc->decl()->rtype(env,args_e,false)); // add defines_var annotation if applicable Id* assignTo = NULL; if (bot==BOT_EQ && ctx.b == C_ROOT) { if (le0 && le0->isa()) { assignTo = le0->cast(); } else if (le1 && le1->isa()) { assignTo = le1->cast(); } if (assignTo) { makeDefinedVar(assignTo->decl()->flat(), cc); } } EnvI::CSEMap::iterator cit = env.cse_map_find(cc); if (cit != env.cse_map_end()) { ees[2].b = cit->second.r(); if (doubleNeg) { Type t = ees[2].b()->type(); ees[2].b = new UnOp(Location().introduce(),UOT_NOT,ees[2].b()); ees[2].b()->type(t); } if (Id* id = ees[2].b()->dyn_cast()) { addCtxAnn(id->decl(),ctx.b); } ret.r = conj(env,r,ctx,ees); GC::unlock(); } else { bool singleExp = true; for (unsigned int i=0; itype(); ees[2].b = new UnOp(Location().introduce(),UOT_NOT,ees[2].b()); ees[2].b()->type(t); } if (Id* id = ees[2].b()->dyn_cast()) { addCtxAnn(id->decl(),ctx.b); } ret.r = conj(env,r,ctx,ees); } } } else { ret.r = conj(env,r,ctx,ees); } } break; case BOT_PLUSPLUS: { std::vector ee(2); EE eev = flat_exp(env,ctx,boe0,NULL,NULL); ee[0] = eev; ArrayLit* al; if (eev.r()->isa()) { al = eev.r()->cast(); } else { Id* id = eev.r()->cast(); if (id->decl()==NULL) { throw InternalError("undefined identifier"); } if (id->decl()->e()==NULL) { throw InternalError("array without initialiser not supported"); } al = follow_id(id)->cast(); } ArrayLit* al0 = al; eev = flat_exp(env,ctx,boe1,NULL,NULL); ee[1] = eev; if (eev.r()->isa()) { al = eev.r()->cast(); } else { Id* id = eev.r()->cast(); if (id->decl()==NULL) { throw InternalError("undefined identifier"); } if (id->decl()->e()==NULL) { throw InternalError("array without initialiser not supported"); } al = follow_id(id)->cast(); } ArrayLit* al1 = al; std::vector v(al0->size()+al1->size()); for (unsigned int i=al0->size(); i--;) v[i] = (*al0)[i]; for (unsigned int i=al1->size(); i--;) v[al0->size()+i] = (*al1)[i]; GCLock lock; ArrayLit* alret = new ArrayLit(e->loc(),v); alret->type(e->type()); ret.b = conj(env,b,Ctx(),ee); ret.r = bind(env,ctx,r,alret); } break; } return ret; } } libminizinc-2.4.2/lib/flatten/flatten_call.cpp000066400000000000000000001254261360574160400214050ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include namespace MiniZinc { std::vector toExpVec(std::vector& v) { std::vector r(v.size()); for (unsigned int i=static_cast(v.size()); i--;) r[i] = v[i](); return r; } bool isTotal(FunctionI* fi) { return fi->ann().contains(constants().ann.promise_total); } Call* same_call(EnvI& env, Expression* e, const ASTString& id) { assert(GC::locked()); Expression* ce = follow_id(e); Call* c = Expression::dyn_cast(ce); if (c) { if (c->id() == id) { return ce->cast(); } else if (c->id() == constants().ids.int2float) { Expression* i2f = follow_id(c->arg(0)); Call* i2fc = Expression::dyn_cast(i2f); if (i2fc && i2fc->id() == id && id==constants().ids.lin_exp) { ArrayLit* coeffs = eval_array_lit(env, i2fc->arg(0)); std::vector ncoeff_v(coeffs->size()); for (unsigned int i=0; isize(); i++) { ncoeff_v[i] = FloatLit::a(eval_int(env, (*coeffs)[i])); } ArrayLit* ncoeff = new ArrayLit(coeffs->loc().introduce(), ncoeff_v); ncoeff->type(Type::parfloat(1)); ArrayLit* vars = eval_array_lit(env, i2fc->arg(1)); std::vector n_vars_v(vars->size()); for (unsigned int i=0; isize(); i++) { Call* f2i = new Call((*vars)[i]->loc().introduce(), constants().ids.int2float, {(*vars)[i]}); f2i->decl(env.model->matchFn(env, f2i, false)); assert(f2i->decl()); f2i->type(Type::varfloat()); EE ee = flat_exp(env, Ctx(), f2i, NULL, constants().var_true); n_vars_v[i] = ee.r(); } ArrayLit* nvars = new ArrayLit(vars->loc().introduce(), n_vars_v); nvars->type(Type::varfloat(1)); FloatVal c = eval_int(env, i2fc->arg(2)); Call* nlinexp = new Call(i2fc->loc().introduce(), constants().ids.lin_exp, {ncoeff, nvars, FloatLit::a(c)}); nlinexp->decl(env.model->matchFn(env, nlinexp, false)); assert(nlinexp->decl()); nlinexp->type(Type::varfloat()); return nlinexp; } } } return NULL; } class CmpExp { public: bool operator ()(const KeepAlive& i, const KeepAlive& j) const { if (Expression::equal(i(),j())) return false; return i()& x, bool identity) { for (unsigned int i=0; iisa()) { if (x[i]()->cast()->v()==identity) { // skip } else { return true; } } else { x[ci++] = x[i]; } } } x.resize(ci); return false; } bool contains_dups(std::vector& x, std::vector& y) { if (x.size()==0 || y.size()==0) return false; unsigned int ix=0; unsigned int iy=0; for (;;) { if (x[ix]()==y[iy]()) return true; if (x[ix]() < y[iy]()) { ix++; } else { iy++; } if (ix==x.size() || iy==y.size()) return false; } } template void flatten_linexp_call(EnvI& env, Ctx ctx, Ctx nctx, ASTString& cid, Call* c, EE& ret, VarDecl* b, VarDecl* r, std::vector& args_ee, std::vector& args) { typedef typename LinearTraits::Val Val; Expression* al_arg = (cid==constants().ids.sum ? args_ee[0].r() : args_ee[1].r()); EE flat_al = flat_exp(env,nctx,al_arg,NULL,NULL); ArrayLit* al = follow_id(flat_al.r())->template cast(); KeepAlive al_ka = al; if (al->dims()>1) { Type alt = al->type(); alt.dim(1); GCLock lock; al = new ArrayLit(al->loc(),*al); al->type(alt); al_ka = al; } Val d = (cid == constants().ids.sum ? Val(0) : LinearTraits::eval(env,args_ee[2].r())); std::vector c_coeff(al->size()); if (cid==constants().ids.sum) { for (unsigned int i=al->size(); i--;) c_coeff[i] = 1; } else { EE flat_coeff = flat_exp(env,nctx,args_ee[0].r(),NULL,NULL); ArrayLit* coeff = follow_id(flat_coeff.r())->template cast(); for (unsigned int i=coeff->size(); i--;) c_coeff[i] = LinearTraits::eval(env,(*coeff)[i]); } cid = constants().ids.lin_exp; std::vector coeffv; std::vector alv; for (unsigned int i=0; isize(); i++) { GCLock lock; if (Call* sc = Expression::dyn_cast(same_call(env,(*al)[i],cid))) { if (VarDecl* alvi_decl = follow_id_to_decl((*al)[i])->dyn_cast()) { if (alvi_decl->ti()->domain()) { // Test if the variable has tighter declared bounds than what can be inferred // from its RHS. If yes, keep the variable (don't aggregate), because the tighter // bounds are actually a constraint typename LinearTraits::Domain sc_dom = LinearTraits::eval_domain(env,alvi_decl->ti()->domain()); typename LinearTraits::Bounds sc_bounds = LinearTraits::compute_bounds(env,sc); if (LinearTraits::domain_tighter(sc_dom, sc_bounds)) { coeffv.push_back(c_coeff[i]); alv.push_back((*al)[i]); continue; } } } Val cd = c_coeff[i]; ArrayLit* sc_coeff = eval_array_lit(env,sc->arg(0)); ArrayLit* sc_al = eval_array_lit(env,sc->arg(1)); Val sc_d = LinearTraits::eval(env,sc->arg(2)); assert(sc_coeff->size() == sc_al->size()); for (unsigned int j=0; jsize(); j++) { coeffv.push_back(cd*LinearTraits::eval(env,(*sc_coeff)[j])); alv.push_back((*sc_al)[j]); } d += cd*sc_d; } else { coeffv.push_back(c_coeff[i]); alv.push_back((*al)[i]); } } simplify_lin(coeffv,alv,d); if (coeffv.size()==0) { GCLock lock; ret.b = conj(env,b,Ctx(),args_ee); ret.r = bind(env,ctx,r,LinearTraits::newLit(d)); return; } else if (coeffv.size()==1 && coeffv[0]==1 && d==0) { ret.b = conj(env,b,Ctx(),args_ee); ret.r = bind(env,ctx,r,alv[0]()); return; } GCLock lock; std::vector coeff_ev(coeffv.size()); for (unsigned int i=static_cast(coeff_ev.size()); i--;) coeff_ev[i] = LinearTraits::newLit(coeffv[i]); ArrayLit* ncoeff = new ArrayLit(Location().introduce(),coeff_ev); Type t = coeff_ev[0]->type(); t.dim(1); ncoeff->type(t); args.push_back(ncoeff); std::vector alv_e(alv.size()); bool al_same_as_before = alv.size()==al->size(); for (unsigned int i=static_cast(alv.size()); i--;) { alv_e[i] = alv[i](); al_same_as_before = al_same_as_before && Expression::equal(alv_e[i],(*al)[i]); } if (al_same_as_before) { Expression* rd = follow_id_to_decl(flat_al.r()); if (rd->isa()) rd = rd->cast()->id(); if (rd->type().dim()>1) { ArrayLit* al = eval_array_lit(env,rd); std::vector > dims(1); dims[0].first = 1; dims[0].second = al->size(); rd = new ArrayLit(al->loc(),*al,dims); Type t = al->type(); t.dim(1); rd->type(t); } args.push_back(rd); } else { ArrayLit* nal = new ArrayLit(al->loc(),alv_e); nal->type(al->type()); args.push_back(nal); } Lit* il = LinearTraits::newLit(d); args.push_back(il); } /// Special form of disjunction for SCIP bool addBoundsDisj(EnvI& env, Expression* arg, Call* c_orig) { auto pArrayLit = arg->dyn_cast(); if (nullptr == pArrayLit) return false; std::vector isUBI, bndI, varI, // integer bounds and vars isUBF, bndF, varF; // float bounds and vars for (int i=pArrayLit->size(); i--; ) { auto pId=pArrayLit->operator [](i)->dyn_cast(); if (nullptr==pId) return false; auto pDecl=follow_id_to_decl(pId)->dyn_cast(); /// Checking the rhs auto pRhs=pDecl->e(); if (nullptr==pRhs) return false; // not checking this boolean auto pCall=pRhs->dyn_cast(); if (nullptr==pCall) return false; if (constants().ids.int_.le!=pCall->id() && constants().ids.float_.le!=pCall->id()) return false; /// See if one is a constant and one a variable Expression *pConst=nullptr, *pVar=nullptr; bool fFloat=false; bool isUB=false; for (int j=pCall->n_args(); j--; ) { if (auto pF=pCall->arg(j)->dyn_cast()) { pConst=pF; fFloat=true; isUB = (1==j); } else if (auto pF=pCall->arg(j)->dyn_cast()) { pConst=pF; fFloat=false; isUB = (1==j); } else if (auto pId=pCall->arg(j)->dyn_cast()) { if (nullptr!=pVar) return false; // 2 variables, exit pVar = pId; } } /// All good, add them if (fFloat) { isUBF.push_back( constants().boollit(isUB) ); bndF.push_back(pConst); varF.push_back(pVar); } else { isUBI.push_back( constants().boollit(isUB) ); bndI.push_back(pConst); varI.push_back(pVar); } } /// Create new call GCLock lock; auto loc = c_orig->loc().introduce(); std::vector args = { new ArrayLit(loc, isUBI), new ArrayLit(loc, bndI), new ArrayLit(loc, varI), new ArrayLit(loc, isUBF), new ArrayLit(loc, bndF), new ArrayLit(loc, varF) }; Call* c = new Call(c_orig->loc().introduce(), env.model->getFnDecls().bounds_disj.second->id(), args); c->type(Type::varbool()); c->decl(env.model->getFnDecls().bounds_disj.second); env.flat_addItem(new ConstraintI(c_orig->loc().introduce(), c)); return true; } class IgnorePartial { public: EnvI& env; bool ignorePartial; IgnorePartial(EnvI& env0, Call* c) : env(env0), ignorePartial(env.ignorePartial) { if (c->id().endsWith("_reif") || c->id().endsWith("_imp")) { env.ignorePartial = true; } } ~IgnorePartial(void) { env.ignorePartial = ignorePartial; } }; EE flatten_call(EnvI& env,Ctx ctx, Expression* e, VarDecl* r, VarDecl* b) { EE ret; Call* c = e->cast(); IgnorePartial ignorePartial(env,c); if (c->id().endsWith("_reif")) { env.n_reif_ct++; } else if (c->id().endsWith("_imp")) { env.n_imp_ct++; } FunctionI* decl = env.model->matchFn(env,c,false); if (decl == NULL) { throw InternalError("undeclared function or predicate " +c->id().str()); } Ctx nctx = ctx; nctx.neg = false; ASTString cid = c->id(); CallStackItem _csi(env,e); if (cid == constants().ids.bool2int && c->type().dim()==0) { if (ctx.neg) { ctx.neg = false; nctx.neg = true; nctx.b = -ctx.i; } else { nctx.b = ctx.i; } } else if (cid == constants().ids.forall) { nctx.b = +nctx.b; if (ctx.neg) { ctx.neg = false; nctx.neg = true; cid = constants().ids.exists; } } else if (cid == constants().ids.exists) { nctx.b = +nctx.b; if (ctx.neg) { ctx.neg = false; nctx.neg = true; cid = constants().ids.forall; } } else if (decl->e()==NULL && (cid == constants().ids.assert || cid == constants().ids.trace || cid == constants().ids.mzn_deprecate)) { if (cid == constants().ids.assert && c->n_args()==2) { (void) decl->_builtins.b(env,c); ret = flat_exp(env,ctx,constants().lit_true,r,b); } else { KeepAlive callres = decl->_builtins.e(env,c); ret = flat_exp(env,ctx,callres(),r,b); // This is all we need to do for assert, so break out of the E_CALL } return ret; } else if (decl->e() && ctx.b==C_ROOT && decl->e()->isa() && eval_bool(env,decl->e())) { bool allBool = true; for (unsigned int i=0; in_args(); i++) { if (c->arg(i)->type().bt()!=Type::BT_BOOL) { allBool = false; break; } } if (allBool) { ret.r = bind(env,ctx,r,constants().lit_true); ret.b = bind(env,ctx,b,constants().lit_true); return ret; } } if (ctx.b==C_ROOT && decl->e()==NULL && cid == constants().ids.forall && r==constants().var_true) { ret.b = bind(env,ctx,b,constants().lit_true); ArrayLit* al; if (c->arg(0)->isa()) { al = c->arg(0)->cast(); } else { EE flat_al = flat_exp(env,Ctx(),c->arg(0),constants().var_ignore,constants().var_true); al = follow_id(flat_al.r())->cast(); } nctx.b = C_ROOT; for (unsigned int i=0; isize(); i++) (void) flat_exp(env,nctx,(*al)[i],r,b); ret.r = bind(env,ctx,r,constants().lit_true); } else { if (decl->e() && decl->params().size()==1 && decl->e()->isa() && decl->params()[0]->ti()->domain()==NULL && decl->e()->cast()->decl() == decl->params()[0]) { Expression* arg = c->arg(0); for (ExpressionSetIter esi = decl->e()->ann().begin(); esi != decl->e()->ann().end(); ++esi) { arg->addAnnotation(*esi); } for (ExpressionSetIter esi = c->ann().begin(); esi != c->ann().end(); ++esi) { arg->addAnnotation(*esi); } ret = flat_exp(env, ctx, c->arg(0), r, b); return ret; } std::vector args_ee(c->n_args()); bool isPartial = false; if (cid == constants().ids.lin_exp && c->type().isint()) { // Linear expressions need special context handling: // the context of a variable expression depends on the corresponding coefficient // flatten the coefficient array Expression* tmp = follow_id_to_decl(c->arg(0)); ArrayLit* coeffs; if (VarDecl* vd = tmp->dyn_cast()) tmp = vd->id(); { CallArgItem cai(env); args_ee[0] = flat_exp(env,nctx,tmp,NULL,NULL); isPartial |= isfalse(env, args_ee[0].b()); coeffs = eval_array_lit(env, args_ee[0].r()); } ArrayLit* vars = eval_array_lit(env, c->arg(1)); if (vars->flat()) { args_ee[1].r = vars; args_ee[1].b = constants().var_true; } else { CallArgItem cai(env); CallStackItem _csi(env,c->arg(1)); std::vector elems_ee(vars->size()); for (unsigned int i=vars->size(); i--;) { Ctx argctx = nctx; argctx.i = eval_int(env,(*coeffs)[i])<0 ? -nctx.i : +nctx.i; elems_ee[i] = flat_exp(env,argctx,(*vars)[i],NULL,NULL); } std::vector elems(elems_ee.size()); for (unsigned int i=static_cast(elems.size()); i--;) elems[i] = elems_ee[i].r(); KeepAlive ka; { GCLock lock; ArrayLit* alr = new ArrayLit(Location().introduce(),elems); alr->type(vars->type()); alr->flat(true); ka = alr; } args_ee[1].r = ka(); args_ee[1].b = conj(env,b,Ctx(),elems_ee); } { Expression* constant = follow_id_to_decl(c->arg(2)); if (VarDecl* vd = constant->dyn_cast()) constant = vd->id(); CallArgItem cai(env); args_ee[2] = flat_exp(env,nctx,constant,NULL,NULL); isPartial |= isfalse(env, args_ee[2].b()); } } else { bool mixContext = (cid != constants().ids.forall && cid != constants().ids.exists && (cid != constants().ids.bool2int || c->type().dim()>0) && cid != constants().ids.sum && cid != "assert" && cid != constants().var_redef->id() && cid != "mzn_reverse_map_var"); if (cid == "mzn_reverse_map_var") { env.in_reverse_map_var = true; } if (cid == constants().ids.clause && c->arg(0)->isa() && c->arg(1)->isa()) { GCLock lock; // try to make negative arguments positive std::vector newPositives; std::vector newNegatives; ArrayLit* al_neg = c->arg(1)->cast(); for (unsigned int i=0; isize(); i++) { BinOp* bo = (*al_neg)[i]->dyn_cast(); Call* co = (*al_neg)[i]->dyn_cast(); if (bo || (co && (co->id()==constants().ids.forall || co->id()==constants().ids.exists || co->id()==constants().ids.clause))) { UnOp* notBoe0 = new UnOp(Location().introduce(), UOT_NOT, (*al_neg)[i]); notBoe0->type(Type::varbool()); newPositives.push_back(notBoe0); } else { newNegatives.push_back((*al_neg)[i]); } } if (!newPositives.empty()) { ArrayLit* al_pos = c->arg(0)->cast(); for (unsigned int i=0; isize(); i++) { newPositives.push_back((*al_pos)[i]); } c->arg(0, new ArrayLit(Location().introduce(), newPositives)); c->arg(1, new ArrayLit(Location().introduce(), newNegatives)); c->arg(0)->type(Type::varbool(1)); c->arg(1)->type(Type::varbool(1)); } } for (unsigned int i=c->n_args(); i--;) { Ctx argctx = nctx; if (mixContext) { if (cid==constants().ids.clause) { argctx.b = (i==0 ? +nctx.b : -nctx.b); } else if (c->arg(i)->type().bt()==Type::BT_BOOL) { argctx.b = C_MIX; } else if (c->arg(i)->type().bt()==Type::BT_INT) { argctx.i = C_MIX; } } else if (cid == constants().ids.sum && c->arg(i)->type().bt()==Type::BT_BOOL) { argctx.b = argctx.i; } Expression* tmp = follow_id_to_decl(c->arg(i)); if (VarDecl* vd = tmp->dyn_cast()) tmp = vd->id(); CallArgItem cai(env); args_ee[i] = flat_exp(env,argctx,tmp,NULL,NULL); isPartial |= isfalse(env, args_ee[i].b()); } } if (isPartial && c->type().isbool() && !c->type().isopt()) { ret.b = bind(env,Ctx(),b,constants().lit_true); args_ee.resize(1); args_ee[0] = EE(NULL, constants().lit_false); ret.r = conj(env, r, ctx, args_ee); return ret; } std::vector args; if (decl->e()==NULL && (cid == constants().ids.exists || cid == constants().ids.clause)) { std::vector pos_alv; std::vector neg_alv; std::vector pos_stack; std::vector neg_stack; ArrayLit* al_pos = follow_id(args_ee[0].r())->cast(); for (unsigned int i=0; isize(); i++) { pos_stack.push_back((*al_pos)[i]); } if (cid == constants().ids.clause) { ArrayLit* al_neg = follow_id(args_ee[1].r())->cast(); for (unsigned int i=0; isize(); i++) { neg_stack.push_back((*al_neg)[i]); } } while (!pos_stack.empty() || !neg_stack.empty()) { while (!pos_stack.empty()) { Expression* cur = pos_stack.back(); pos_stack.pop_back(); GCLock lock; if (Call* sc = Expression::dyn_cast(same_call(env,cur,constants().ids.exists))) { GCLock lock; ArrayLit* sc_c = eval_array_lit(env,sc->arg(0)); for (unsigned int j=0; jsize(); j++) { pos_stack.push_back((*sc_c)[j]); } } else if (Call* sc = Expression::dyn_cast(same_call(env,cur,constants().ids.clause))) { GCLock lock; ArrayLit* sc_c = eval_array_lit(env,sc->arg(0)); for (unsigned int j=0; jsize(); j++) { pos_stack.push_back((*sc_c)[j]); } sc_c = eval_array_lit(env,sc->arg(1)); for (unsigned int j=0; jsize(); j++) { neg_stack.push_back((*sc_c)[j]); } } else { Call* eq_call = Expression::dyn_cast(same_call(env,cur,constants().ids.bool_eq)); if (eq_call && Expression::equal(eq_call->arg(1),constants().lit_false)) { neg_stack.push_back(eq_call->arg(0)); } else if (eq_call && Expression::equal(eq_call->arg(0),constants().lit_false)) { neg_stack.push_back(eq_call->arg(1)); } else if (eq_call && Expression::equal(eq_call->arg(1),constants().lit_true)) { pos_stack.push_back(eq_call->arg(0)); } else if (eq_call && Expression::equal(eq_call->arg(0),constants().lit_true)) { pos_stack.push_back(eq_call->arg(1)); } else if (Id* ident = cur->dyn_cast()) { if (ident->decl()->ti()->domain()!=constants().lit_false) { pos_alv.push_back(ident); } } else { pos_alv.push_back(cur); } } } while (!neg_stack.empty()) { GCLock lock; Expression* cur = neg_stack.back(); neg_stack.pop_back(); if (Call* sc = Expression::dyn_cast(same_call(env,cur,constants().ids.forall))) { GCLock lock; ArrayLit* sc_c = eval_array_lit(env,sc->arg(0)); for (unsigned int j=0; jsize(); j++) { neg_stack.push_back((*sc_c)[j]); } } else { Call* eq_call = Expression::dyn_cast(same_call(env,cur,constants().ids.bool_eq)); if (eq_call && Expression::equal(eq_call->arg(1),constants().lit_false)) { pos_stack.push_back(eq_call->arg(0)); } else if (eq_call && Expression::equal(eq_call->arg(0),constants().lit_false)) { pos_stack.push_back(eq_call->arg(1)); } else if (eq_call && Expression::equal(eq_call->arg(1),constants().lit_true)) { neg_stack.push_back(eq_call->arg(0)); } else if (eq_call && Expression::equal(eq_call->arg(0),constants().lit_true)) { neg_stack.push_back(eq_call->arg(1)); } else if (Id* ident = cur->dyn_cast()) { if (ident->decl()->ti()->domain()!=constants().lit_true) { neg_alv.push_back(ident); } } else { neg_alv.push_back(cur); } } } } bool subsumed = remove_dups(pos_alv,false); subsumed = subsumed || remove_dups(neg_alv,true); subsumed = subsumed || contains_dups(pos_alv, neg_alv); if (subsumed) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,ctx,r,constants().lit_true); return ret; } if (neg_alv.empty()) { if (pos_alv.size()==0) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,ctx,r,constants().lit_false); return ret; } else if (pos_alv.size()==1) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,ctx,r,pos_alv[0]()); return ret; } GCLock lock; ArrayLit* nal = new ArrayLit(Location().introduce(),toExpVec(pos_alv)); nal->type(Type::varbool(1)); args.push_back(nal); cid = constants().ids.exists; } else { GCLock lock; ArrayLit* pos_al = new ArrayLit(Location().introduce(),toExpVec(pos_alv)); pos_al->type(Type::varbool(1)); ArrayLit* neg_al = new ArrayLit(Location().introduce(),toExpVec(neg_alv)); neg_al->type(Type::varbool(1)); cid = constants().ids.clause; args.push_back(pos_al); args.push_back(neg_al); } if (C_ROOT==ctx.b && cid == constants().ids.exists) { /// Check the special bounds disjunction for SCIP /// Only in root context if (!env.model->getFnDecls().bounds_disj.first) { env.model->getFnDecls().bounds_disj.first = true; std::vector bj_t = { Type::parbool(1), Type::parint(1), Type::varint(1), Type::parbool(1), Type::parfloat(1), Type::varfloat(1) }; GCLock lock; env.model->getFnDecls().bounds_disj.second = env.model->matchFn(env, ASTString("bounds_disj"), bj_t, false); } /// When the SCIP predicate is declared only bool fBoundsDisj_Maybe = ( nullptr != env.model->getFnDecls().bounds_disj.second ); if (fBoundsDisj_Maybe) { if (addBoundsDisj(env, args[0](), c)) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,ctx,r,constants().lit_true); return ret; } } } } else if (decl->e()==NULL && cid == constants().ids.forall) { ArrayLit* al = follow_id(args_ee[0].r())->cast(); std::vector alv; for (unsigned int i=0; isize(); i++) { GCLock lock; if (Call* sc = Expression::dyn_cast(same_call(env,(*al)[i],cid))) { GCLock lock; ArrayLit* sc_c = eval_array_lit(env,sc->arg(0)); for (unsigned int j=0; jsize(); j++) { alv.push_back((*sc_c)[j]); } } else { alv.push_back((*al)[i]); } } bool subsumed = remove_dups(alv,true); if (subsumed) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,ctx,r,constants().lit_false); return ret; } if (alv.size()==0) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,ctx,r,constants().lit_true); return ret; } else if (alv.size()==1) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,ctx,r,alv[0]()); return ret; } GCLock lock; ArrayLit* nal = new ArrayLit(al->loc(),toExpVec(alv)); nal->type(al->type()); args.push_back(nal); } else if (decl->e()==NULL && (cid == constants().ids.lin_exp || cid==constants().ids.sum)) { if (e->type().isint()) { flatten_linexp_call(env,ctx,nctx,cid,c,ret,b,r,args_ee,args); } else { flatten_linexp_call(env,ctx,nctx,cid,c,ret,b,r,args_ee,args); } if (args.size()==0) return ret; } else { for (unsigned int i=0; ie() != nullptr); KeepAlive cr; { GCLock lock; std::vector e_args = toExpVec(args); Call* cr_c = new Call(c->loc().introduce(),cid,e_args); decl = env.model->matchFn(env,cr_c,false); if (decl==NULL) throw FlatteningError(env,cr_c->loc(), "cannot find matching declaration"); cr_c->type(decl->rtype(env,e_args,false)); assert(decl); cr_c->decl(decl); cr = cr_c; } if (hadImplementation && decl->e()==NULL && (cid == constants().ids.lin_exp || cid==constants().ids.sum)) { args.clear(); if (e->type().isint()) { flatten_linexp_call(env,ctx,nctx,cid,cr()->cast(),ret,b,r,args_ee,args); } else { flatten_linexp_call(env,ctx,nctx,cid,cr()->cast(),ret,b,r,args_ee,args); } if (args.size()==0) return ret; GCLock lock; std::vector e_args = toExpVec(args); Call* cr_c = new Call(c->loc().introduce(),cid,e_args); decl = env.model->matchFn(env,cr_c,false); if (decl==NULL) throw FlatteningError(env,cr_c->loc(), "cannot find matching declaration"); cr_c->type(decl->rtype(env,e_args,false)); assert(decl); cr_c->decl(decl); cr = cr_c; } EnvI::CSEMap::iterator cit = env.cse_map_find(cr()); if (cit != env.cse_map_end()) { ret.b = bind(env,Ctx(),b,env.ignorePartial ? constants().lit_true : cit->second.b()); ret.r = bind(env,ctx,r,cit->second.r()); } else { for (unsigned int i=0; iparams().size(); i++) { if (decl->params()[i]->type().dim() > 0) { // Check array index sets ArrayLit* al = follow_id(args[i]())->cast(); VarDecl* pi = decl->params()[i]; for (unsigned int j=0; jti()->ranges().size(); j++) { TypeInst* range_ti = pi->ti()->ranges()[j]; if (range_ti->domain() && !range_ti->domain()->isa()) { GCLock lock; IntSetVal* isv = eval_intset(env, range_ti->domain()); if (isv->min() != al->min(j) || isv->max() != al->max(j)) { std::ostringstream oss; oss << "array index set " << (j+1) << " of argument " << (i+1) << " does not match declared index set"; throw FlatteningError(env, e->loc(), oss.str()); } } } } if (Expression* dom = decl->params()[i]->ti()->domain()) { if (!dom->isa()) { // May have to constrain actual argument if (args[i]()->type().bt() == Type::BT_INT) { GCLock lock; IntSetVal* isv = eval_intset(env,dom); BinOpType bot; bool needToConstrain; if (args[i]()->type().st() == Type::ST_SET) { bot = BOT_SUBSET; needToConstrain = true; } else { bot = BOT_IN; if (args[i]()->type().dim() > 0) { needToConstrain = true; } else { IntBounds ib = compute_int_bounds(env,args[i]()); needToConstrain = !ib.valid || isv->size()==0 || ib.l < isv->min(0) || ib.u > isv->max(isv->size()-1); } } if (needToConstrain) { GCLock lock; Expression* domconstraint; if (args[i]()->type().dim() > 0) { std::vector domargs(2); domargs[0] = args[i](); domargs[1] = dom; Call* c = new Call(Location().introduce(),"var_dom",domargs); c->type(Type::varbool()); c->decl(env.model->matchFn(env,c,false)); if (c->decl()==NULL) throw InternalError("no matching declaration found for var_dom"); domconstraint = c; } else { domconstraint = new BinOp(Location().introduce(),args[i](),bot,dom); } domconstraint->type(args[i]()->type().ispar() ? Type::parbool() : Type::varbool()); if (ctx.b == C_ROOT) { (void) flat_exp(env, Ctx(), domconstraint, constants().var_true, constants().var_true); } else { EE ee = flat_exp(env, Ctx(), domconstraint, NULL, constants().var_true); ee.b = ee.r; args_ee.push_back(ee); } } } else if (args[i]()->type().bt() == Type::BT_FLOAT) { GCLock lock; FloatSetVal* fsv = eval_floatset(env,dom); bool needToConstrain; if (args[i]()->type().dim() > 0) { needToConstrain = true; } else { FloatBounds fb = compute_float_bounds(env,args[i]()); needToConstrain = !fb.valid || fsv->size()==0 || fb.l < fsv->min(0) || fb.u > fsv->max(fsv->size()-1); } if (needToConstrain) { GCLock lock; Expression* domconstraint; if (args[i]()->type().dim() > 0) { std::vector domargs(2); domargs[0] = args[i](); domargs[1] = dom; Call* c = new Call(Location().introduce(),"var_dom",domargs); c->type(Type::varbool()); c->decl(env.model->matchFn(env,c,false)); if (c->decl()==NULL) throw InternalError("no matching declaration found for var_dom"); domconstraint = c; } else { domconstraint = new BinOp(Location().introduce(),args[i](),BOT_IN,dom); } domconstraint->type(args[i]()->type().ispar() ? Type::parbool() : Type::varbool()); if (ctx.b == C_ROOT) { (void) flat_exp(env, Ctx(), domconstraint, constants().var_true, constants().var_true); } else { EE ee = flat_exp(env, Ctx(), domconstraint, NULL, constants().var_true); ee.b = ee.r; args_ee.push_back(ee); } } } else if (args[i]()->type().bt() == Type::BT_BOT) { // Nothing to be done for empty arrays/sets } else { throw EvalError(env,decl->params()[i]->loc(),"domain restrictions other than int and float not supported yet"); } } } } if (cr()->type().isbool() && !cr()->type().ispar() && !cr()->type().isopt() && (ctx.b != C_ROOT || r != constants().var_true)) { std::vector argtypes(args.size()); for (unsigned int i=0; itype(); argtypes.push_back(Type::varbool()); GCLock lock; ASTString r_cid = env.reifyId(cid); FunctionI* reif_decl = env.model->matchFn(env, r_cid, argtypes, false); if (reif_decl && reif_decl->e()) { addPathAnnotation(env, reif_decl->e()); VarDecl* reif_b; if (r==NULL || (r != NULL && r->e() != NULL)) { reif_b = newVarDecl(env, Ctx(), new TypeInst(Location().introduce(),Type::varbool()), NULL, NULL, NULL); addCtxAnn(reif_b, ctx.b); if (reif_b->ti()->domain()) { if (reif_b->ti()->domain() == constants().lit_true) { bind(env,ctx,r,constants().lit_true); r = constants().var_true; ctx.b = C_ROOT; goto call_nonreif; } else { std::vector args_e(args.size()+1); for (unsigned int i=0; itype(Type::varbool()); reif_call->decl(reif_decl); flat_exp(env, Ctx(), reif_call, constants().var_true, constants().var_true); args_ee.push_back(EE(NULL,constants().lit_false)); ret.r = conj(env,r,ctx,args_ee); ret.b = bind(env,ctx,b,constants().lit_true); return ret; } } } else { reif_b = r; } // Annotate cr() with getPath() addPathAnnotation(env, cr()); reif_b->e(cr()); if (r != NULL && r->e() != NULL) { Ctx reif_ctx; reif_ctx.neg = ctx.neg; bind(env,reif_ctx,r,reif_b->id()); } env.vo_add_exp(reif_b); ret.b = bind(env,Ctx(),b,constants().lit_true); args_ee.push_back(EE(NULL,reif_b->id())); ret.r = conj(env,NULL,ctx,args_ee); if (!ctx.neg && !cr()->type().isann()) { env.cse_map_insert(cr(),ret); } return ret; } } call_nonreif: if ( (cr()->type().ispar() && !cr()->type().isann()) || decl->e()==NULL) { Call* cr_c = cr()->cast(); /// All builtins are total std::vector argt(cr_c->n_args()); for (unsigned int i=static_cast(argt.size()); i--;) argt[i] = cr_c->arg(i)->type(); Type callt = decl->rtype(env,argt,false); if (callt.ispar() && callt.bt()!=Type::BT_ANN) { GCLock lock; try { ret.r = bind(env,ctx,r,eval_par(env,cr_c)); ret.b = conj(env,b,Ctx(),args_ee); } catch (ResultUndefinedError&) { ret.r = createDummyValue(env, cr_c->type()); ret.b = bind(env,Ctx(),b,constants().lit_false); return ret; } // Do not insert into map, since par results will quickly become // garbage anyway and then disappear from the map } else if (decl->_builtins.e) { KeepAlive callres; { GCLock lock; callres = decl->_builtins.e(env,cr_c); } EE res = flat_exp(env,ctx,callres(),r,b); args_ee.push_back(res); ret.b = conj(env,b,Ctx(),args_ee); addPathAnnotation(env, res.r()); ret.r = bind(env,ctx,r,res.r()); if (!ctx.neg && !cr_c->type().isann()) env.cse_map_insert(cr_c,ret); } else { ret.b = conj(env,b,Ctx(),args_ee); addPathAnnotation(env, cr_c); ret.r = bind(env,ctx,r,cr_c); if (!ctx.neg && !cr_c->type().isann()) env.cse_map_insert(cr_c,ret); } } else { std::vector previousParameters(decl->params().size()); for (unsigned int i=decl->params().size(); i--;) { VarDecl* vd = decl->params()[i]; previousParameters[i] = vd->e(); vd->flat(vd); vd->e(args[i]()); } if (decl->e()->type().isbool() && !decl->e()->type().isopt()) { ret.b = bind(env,Ctx(),b,constants().lit_true); if (ctx.b==C_ROOT && r==constants().var_true) { (void) flat_exp(env,Ctx(),decl->e(),r,constants().var_true); } else { Ctx nctx; if (!isTotal(decl)) { nctx = ctx; nctx.neg = false; } EE ee = flat_exp(env,nctx,decl->e(),NULL,constants().var_true); ee.b = ee.r; args_ee.push_back(ee); } ret.r = conj(env,r,ctx,args_ee); } else { if (isTotal(decl)) { EE ee = flat_exp(env,Ctx(),decl->e(),r,constants().var_true); ret.r = bind(env,ctx,r,ee.r()); } else { ret = flat_exp(env,ctx,decl->e(),r,NULL); args_ee.push_back(ret); if (decl->e()->type().dim() > 0) { ArrayLit* al = follow_id(ret.r())->cast(); assert(al->dims() == decl->e()->type().dim()); for (unsigned int i=0; iti()->ranges().size(); i++) { if (decl->ti()->ranges()[i]->domain() && !decl->ti()->ranges()[i]->domain()->isa()) { GCLock lock; IntSetVal* isv = eval_intset(env, decl->ti()->ranges()[i]->domain()); if (al->min(i) != isv->min() || al->max(i) != isv->max()) { EE ee; ee.b = constants().lit_false; args_ee.push_back(ee); } } } } if (decl->ti()->domain() && !decl->ti()->domain()->isa()) { BinOpType bot; if (ret.r()->type().st() == Type::ST_SET) { bot = BOT_SUBSET; } else { bot = BOT_IN; } KeepAlive domconstraint; if (decl->e()->type().dim() > 0) { GCLock lock; std::vector domargs(2); domargs[0] = ret.r(); domargs[1] = decl->ti()->domain(); Call* c = new Call(Location().introduce(),"var_dom",domargs); c->type(Type::varbool()); c->decl(env.model->matchFn(env,c,false)); if (c->decl()==NULL) throw InternalError("no matching declaration found for var_dom"); domconstraint = c; } else { GCLock lock; domconstraint = new BinOp(Location().introduce(),ret.r(),bot,decl->ti()->domain()); } domconstraint()->type(ret.r()->type().ispar() ? Type::parbool() : Type::varbool()); if (ctx.b == C_ROOT) { (void) flat_exp(env, Ctx(), domconstraint(), constants().var_true, constants().var_true); } else { EE ee = flat_exp(env, Ctx(), domconstraint(), NULL, constants().var_true); ee.b = ee.r; args_ee.push_back(ee); } } } ret.b = conj(env,b,Ctx(),args_ee); } if (!ctx.neg && !cr()->type().isann()) env.cse_map_insert(cr(),ret); // Restore previous mapping for (unsigned int i=decl->params().size(); i--;) { VarDecl* vd = decl->params()[i]; vd->e(previousParameters[i]()); vd->flat(vd->e() ? vd : NULL); } } } } if (cid == "mzn_reverse_map_var") { env.in_reverse_map_var = false; } return ret; } } libminizinc-2.4.2/lib/flatten/flatten_comp.cpp000066400000000000000000000200451360574160400214170ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include namespace MiniZinc { EE flatten_comp(EnvI& env,Ctx ctx, Expression* e, VarDecl* r, VarDecl* b) { CallStackItem _csi(env,e); EE ret; Comprehension* c = e->cast(); KeepAlive c_ka(c); if (c->type().isopt()) { std::vector in(c->n_generators()); std::vector orig_where(c->n_generators()); std::vector where; GCLock lock; for (int i=0; in_generators(); i++) { if (c->in(i)==NULL) { in[i] = NULL; orig_where[i] = c->where(i); } else { if (c->in(i)->type().isvar() && c->in(i)->type().dim()==0) { std::vector args(1); args[0] = c->in(i); Call* ub = new Call(Location().introduce(),"ub",args); ub->type(Type::parsetint()); ub->decl(env.model->matchFn(env, ub, false)); in[i] = ub; for (int j=0; jn_decls(i); j++) { BinOp* bo = new BinOp(Location().introduce(),c->decl(i,j)->id(), BOT_IN, c->in(i)); bo->type(Type::varbool()); where.push_back(bo); } } else { in[i] = c->in(i); } if (c->where(i) && c->where(i)->type().isvar()) { // This is a generalised where clause. Split into par and var part. // The par parts can remain in where clause. The var parts are translated // into optionality constraints. if (c->where(i)->isa() && c->where(i)->cast()->op()==BOT_AND) { std::vector parWhere; std::vector todo; todo.push_back(c->where(i)->cast()); while (!todo.empty()) { BinOp* bo = todo.back(); todo.pop_back(); if (bo->rhs()->type().ispar()) { parWhere.push_back(bo->rhs()); } else if (bo->rhs()->isa() && bo->rhs()->cast()->op()==BOT_AND) { todo.push_back(bo->rhs()->cast()); } else { where.push_back(bo->rhs()); } if (bo->lhs()->type().ispar()) { parWhere.push_back(bo->lhs()); } else if (bo->lhs()->isa() && bo->lhs()->cast()->op()==BOT_AND) { todo.push_back(bo->lhs()->cast()); } else { where.push_back(bo->lhs()); } } switch (parWhere.size()) { case 0: orig_where[i] = NULL; break; case 1: orig_where[i] = parWhere[0]; break; case 2: orig_where[i] = new BinOp(c->where(i)->loc(), parWhere[0], BOT_AND, parWhere[1]); orig_where[i]->type(Type::parbool()); break; default: { ArrayLit* parWhereAl = new ArrayLit(c->where(i)->loc(), parWhere); parWhereAl->type(Type::parbool(1)); Call* forall = new Call(c->where(i)->loc(), constants().ids.forall, {parWhereAl}); forall->type(Type::parbool()); forall->decl(env.model->matchFn(env, forall, false)); orig_where[i] = forall; break; } } } else { orig_where[i] = NULL; where.push_back(c->where(i)); } } else { orig_where[i] = c->where(i); } } } if (where.size() > 0) { Generators gs; for (int i=0; in_generators(); i++) { std::vector vds(c->n_decls(i)); for (int j=0; jn_decls(i); j++) vds[j] = c->decl(i, j); gs._g.push_back(Generator(vds,in[i],orig_where[i])); } Expression* cond; if (where.size() > 1) { ArrayLit* al = new ArrayLit(Location().introduce(), where); al->type(Type::varbool(1)); std::vector args(1); args[0] = al; Call* forall = new Call(Location().introduce(), constants().ids.forall, args); forall->type(Type::varbool()); forall->decl(env.model->matchFn(env, forall, false)); cond = forall; } else { cond = where[0]; } Expression* new_e; Call* surround = env.surroundingCall(); Type ntype = c->type(); if (surround && surround->id()==constants().ids.forall) { new_e = new BinOp(Location().introduce(), cond, BOT_IMPL, c->e()); new_e->type(Type::varbool()); ntype.ot(Type::OT_PRESENT); } else if (surround && surround->id()==constants().ids.exists) { new_e = new BinOp(Location().introduce(), cond, BOT_AND, c->e()); new_e->type(Type::varbool()); ntype.ot(Type::OT_PRESENT); } else if (surround && surround->id()==constants().ids.sum) { Call* if_b_else_zero = new Call(c->loc().introduce(), ASTString("if_b_else_zero"), {cond, c->e()}); Type tt; tt = c->e()->type(); tt.ti(Type::TI_VAR); tt.ot(Type::OT_PRESENT); if_b_else_zero->type(tt); new_e = if_b_else_zero; ntype.ot(Type::OT_PRESENT); } else { Call* if_b_else_absent = new Call(c->loc().introduce(), ASTString("if_b_else_absent"), {cond, c->e()}); Type tt; tt = c->e()->type(); tt.ti(Type::TI_VAR); tt.ot(Type::OT_OPTIONAL); if_b_else_absent->type(tt); new_e = if_b_else_absent; } Comprehension* nc = new Comprehension(c->loc(),new_e,gs,c->set()); nc->type(ntype); c = nc; c_ka = c; } } class EvalF { public: Ctx ctx; EvalF(Ctx ctx0) : ctx(ctx0) {} typedef EE ArrayVal; EE e(EnvI& env, Expression* e0) { VarDecl* b = ctx.b==C_ROOT ? constants().var_true : NULL; VarDecl* r = (ctx.b == C_ROOT && e0->type().isbool() && !e0->type().isopt()) ? constants().var_true : NULL; return flat_exp(env,ctx,e0,r,b); } Expression* flatten(EnvI& env, Expression* e0) { return flat_exp(env,Ctx(),e0,NULL,constants().var_true).r(); } } _evalf(ctx); std::vector elems_ee = eval_comp(env,_evalf,c); std::vector elems(elems_ee.size()); Type elemType = Type::bot(); bool allPar = true; for (unsigned int i=static_cast(elems.size()); i--;) { elems[i] = elems_ee[i].r(); if (elemType==Type::bot()) elemType = elems[i]->type(); if (!elems[i]->type().ispar()) allPar = false; } if (elemType.isbot()) { elemType = c->type(); elemType.ti(Type::TI_PAR); } if (!allPar) elemType.ti(Type::TI_VAR); if (c->set()) elemType.st(Type::ST_SET); else elemType.dim(c->type().dim()); KeepAlive ka; { GCLock lock; if (c->set()) { if (c->type().ispar() && allPar) { SetLit* sl = new SetLit(c->loc(), elems); sl->type(elemType); Expression* slr = eval_par(env,sl); slr->type(elemType); ka = slr; } else { throw InternalError("var set comprehensions not supported yet"); } } else { ArrayLit* alr = new ArrayLit(Location().introduce(),elems); alr->type(elemType); alr->flat(true); ka = alr; } } assert(!ka()->type().isbot()); ret.b = conj(env,b,Ctx(),elems_ee); ret.r = bind(env,Ctx(),r,ka()); return ret; } } libminizinc-2.4.2/lib/flatten/flatten_id.cpp000066400000000000000000000160621360574160400210610ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include namespace MiniZinc { EE flatten_id(EnvI& env,Ctx ctx, Expression* e, VarDecl* r, VarDecl* b, bool doNotFollowChains) { CallStackItem _csi(env,e); EE ret; Id* id = e->cast(); if (id->decl()==NULL) { if (id->type().isann()) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,ctx,r,e); return ret; } else { throw FlatteningError(env,e->loc(), "undefined identifier"); } } if (!doNotFollowChains) { Expression* id_f = follow_id_to_decl(id); if (id_f == constants().absent) { ret.b = bind(env,Ctx(),b,constants().lit_true); ret.r = bind(env,ctx,r,id_f); } else { id = id_f->cast()->id(); } } if (ctx.neg && id->type().dim() > 0) { if (id->type().dim() > 1) throw InternalError("multi-dim arrays in negative positions not supported yet"); KeepAlive ka; { GCLock lock; std::vector gen_id(1); gen_id[0] = new VarDecl(id->loc(), new TypeInst(id->loc(),Type::parint()),env.genId(), IntLit::a(0)); /// TODO: support arbitrary dimensions std::vector idxsetargs(1); idxsetargs[0] = id; Call* idxset = new Call(id->loc().introduce(),"index_set",idxsetargs); idxset->decl(env.model->matchFn(env, idxset, false)); idxset->type(idxset->decl()->rtype(env, idxsetargs, false)); Generator gen(gen_id,idxset,NULL); std::vector idx(1); Generators gens; gens._g.push_back(gen); UnOp* aanot = new UnOp(id->loc(),UOT_NOT,NULL); Comprehension* cp = new Comprehension(id->loc(), aanot, gens, false); Id* bodyidx = cp->decl(0,0)->id(); idx[0] = bodyidx; ArrayAccess* aa = new ArrayAccess(id->loc(),id,idx); aanot->e(aa); Type tt = id->type(); tt.dim(0); aa->type(tt); aanot->type(aa->type()); cp->type(id->type()); ctx.neg = false; ka = cp; } ret = flat_exp(env,ctx,ka(),r,b); } else { GCLock lock; VarDecl* vd = id->decl()->flat(); Expression* rete = NULL; if (vd==NULL) { if (id->decl()->e()==NULL || id->decl()->e()->type().isann() || id->decl()->e()->type().isvar() || id->decl()->e()->type().cv() || id->decl()->e()->type().dim() > 0) { // New top-level id, need to copy into env.m vd = flat_exp(env,Ctx(),id->decl(),NULL,constants().var_true).r() ->cast()->decl(); } else { vd = id->decl(); } } ret.b = bind(env,Ctx(),b,constants().lit_true); if (vd->e()!=NULL) { if (vd->e()->type().ispar() && vd->e()->type().dim()==0) { rete = eval_par(env, vd->e()); } else if (vd->e()->isa()) { rete = vd->e(); } } else if (vd->ti()->ranges().size() > 0) { // create fresh variables and array literal std::vector > dims; IntVal asize = 1; for (unsigned int i=0; iti()->ranges().size(); i++) { TypeInst* ti = vd->ti()->ranges()[i]; if (ti->domain()==NULL) throw FlatteningError(env,ti->loc(),"array dimensions unknown"); IntSetVal* isv = eval_intset(env,ti->domain()); if (isv->size() == 0) { dims.push_back(std::pair(1,0)); asize = 0; } else { if (isv->size() != 1) throw FlatteningError(env,ti->loc(),"invalid array index set"); asize *= (isv->max(0)-isv->min(0)+1); dims.push_back(std::pair(static_cast(isv->min(0).toInt()), static_cast(isv->max(0).toInt()))); } } Type tt = vd->ti()->type(); tt.dim(0); if (asize > Constants::max_array_size) { std::ostringstream oss; oss << "array size (" << asize << ") exceeds maximum allowed size (" << Constants::max_array_size << ")"; throw FlatteningError(env,vd->loc(),oss.str()); } std::vector elems(static_cast(asize.toInt())); for (int i=0; i(asize.toInt()); i++) { CallStackItem csi(env, IntLit::a(i)); TypeInst* vti = new TypeInst(Location().introduce(),tt,vd->ti()->domain()); VarDecl* nvd = newVarDecl(env,Ctx(),vti,NULL,vd,NULL); elems[i] = nvd->id(); } // After introducing variables for each array element, the original domain can be // set to "computed" (since it is a consequence of the individual variable domains) vd->ti()->setComputedDomain(true); ArrayLit* al = new ArrayLit(Location().introduce(),elems,dims); al->type(vd->type()); vd->e(al); env.vo_add_exp(vd); EE ee; ee.r = vd; env.cse_map_insert(vd->e(), ee); } if (rete==NULL) { if (!vd->toplevel()) { // create new VarDecl in toplevel, if decl doesnt exist yet EnvI::CSEMap::iterator it = env.cse_map_find(vd->e()); if (it==env.cse_map_end()) { Expression* vde = follow_id(vd->e()); ArrayLit* vdea = vde ? vde->dyn_cast() : NULL; if (vdea && vdea->size()==0) { // Do not create names for empty arrays but return array literal directly rete = vdea; } else { VarDecl* nvd = newVarDecl(env, ctx, eval_typeinst(env,vd), NULL, vd, NULL); if (vd->e()) { (void) flat_exp(env, Ctx(), vd->e(), nvd, constants().var_true); } vd = nvd; EE ee(vd,NULL); if (vd->e()) env.cse_map_insert(vd->e(),ee); } } else { if (it->second.r()->isa()) { vd = it->second.r()->cast(); } else { rete = it->second.r(); } } } if (rete==NULL) { if (id->type().bt() == Type::BT_ANN && vd->e()) { rete = vd->e(); } else { ArrayLit* vda = vd->dyn_cast(); if (vda && vda->size()==0) { // Do not create names for empty arrays but return array literal directly rete = vda; } else { rete = vd->id(); } } } } ret.r = bind(env,ctx,r,rete); } return ret; } EE flatten_id(EnvI& env,Ctx ctx, Expression* e, VarDecl* r, VarDecl* b) { return flatten_id(env,ctx,e,r,b,false); } } libminizinc-2.4.2/lib/flatten/flatten_ite.cpp000066400000000000000000000476331360574160400212560ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include namespace MiniZinc { std::vector get_conjuncts(Expression* e) { std::vector conj_stack; std::vector conjuncts; conj_stack.push_back(e); while (!conj_stack.empty()) { Expression* e = conj_stack.back(); conj_stack.pop_back(); if (BinOp* bo = e->dyn_cast()) { if (bo->op()==BOT_AND) { conj_stack.push_back(bo->rhs()); conj_stack.push_back(bo->lhs()); } else { conjuncts.push_back(e); } } else { conjuncts.push_back(e); } } return conjuncts; } void classify_conjunct(Expression* e, IdMap& eq_occurrences, IdMap >& eq_branches, std::vector& other_branches) { if (BinOp* bo = e->dyn_cast()) { if (bo->op()==BOT_EQ) { if (Id* ident = bo->lhs()->dyn_cast()) { if (eq_branches.find(ident)==eq_branches.end()) { IdMap::iterator it = eq_occurrences.find(ident); if (it==eq_occurrences.end()) { eq_occurrences.insert(ident, 1); } else { eq_occurrences.get(ident)++; } eq_branches.insert(ident, std::make_pair(bo->rhs(),bo)); return; } } else if (Id* ident = bo->rhs()->dyn_cast()) { if (eq_branches.find(ident)==eq_branches.end()) { IdMap::iterator it = eq_occurrences.find(ident); if (it==eq_occurrences.end()) { eq_occurrences.insert(ident, 1); } else { eq_occurrences.get(ident)++; } eq_branches.insert(ident, std::make_pair(bo->lhs(),bo)); return; } } } } other_branches.push_back(e); } EE flatten_ite(EnvI& env,Ctx ctx, Expression* e, VarDecl* r, VarDecl* b) { CallStackItem _csi(env,e); ITE* ite = e->cast(); // The conditions of each branch of the if-then-else std::vector conditions; // Whether the right hand side of each branch is defined std::vector > defined; // The right hand side of each branch std::vector > branches; // Whether all branches are fixed std::vector allBranchesPar; // Compute bounds of result as union bounds of all branches std::vector> r_bounds_int; std::vector r_bounds_valid_int; std::vector> r_bounds_set; std::vector r_bounds_valid_set; std::vector> r_bounds_float; std::vector r_bounds_valid_float; bool allConditionsPar = true; bool allDefined = true; // The result variables of each generated conditional std::vector results; // The then-expressions of each generated conditional std::vector > e_then; // The else-expressions of each generated conditional std::vector e_else; bool noOtherBranches = true; if (ite->type()==Type::varbool() && ctx.b==C_ROOT && r==constants().var_true) { // Check if all branches are of the form x1=e1 /\ ... /\ xn=en IdMap eq_occurrences; std::vector > > eq_branches(ite->size()+1); std::vector > other_branches(ite->size()+1); for (int i=0; isize(); i++) { auto conjuncts = get_conjuncts(ite->e_then(i)); for (auto c : conjuncts) { classify_conjunct(c, eq_occurrences, eq_branches[i], other_branches[i]); } noOtherBranches = noOtherBranches && other_branches[i].empty(); } { auto conjuncts = get_conjuncts(ite->e_else()); for (auto c : conjuncts) { classify_conjunct(c, eq_occurrences, eq_branches[ite->size()], other_branches[ite->size()]); } noOtherBranches = noOtherBranches && other_branches[ite->size()].empty(); } for (auto& e : eq_occurrences) { if (e.second>=ite->size()) { // Any identifier that occurs in all or all but one branch gets its own conditional results.push_back(e.first->decl()); e_then.push_back(std::vector()); for (int i=0; isize(); i++) { IdMap >::iterator it = eq_branches[i].find(e.first); if (it==eq_branches[i].end()) { // not found, simply push x=x e_then.back().push_back(e.first); } else { e_then.back().push_back(it->second.first); } } { IdMap >::iterator it = eq_branches[ite->size()].find(e.first); if (it==eq_branches[ite->size()].end()) { // not found, simply push x=x e_else.push_back(e.first); } else { e_else.push_back(it->second.first); } } } else { // All other identifiers are put in the vector of "other" branches for (int i=0; i<=ite->size(); i++) { IdMap >::iterator it = eq_branches[i].find(e.first); if (it!=eq_branches[i].end()) { other_branches[i].push_back(it->second.second); noOtherBranches = false; eq_branches[i].remove(e.first); } } } } if (!noOtherBranches) { results.push_back(r); e_then.push_back(std::vector()); for (int i=0; isize(); i++) { if (eq_branches[i].size()==0) { e_then.back().push_back(ite->e_then(i)); } else if (other_branches[i].size()==0) { e_then.back().push_back(constants().lit_true); } else if (other_branches[i].size()==1) { e_then.back().push_back(other_branches[i][0]); } else { GCLock lock; ArrayLit* al = new ArrayLit(Location().introduce(), other_branches[i]); al->type(Type::varbool(1)); Call* forall = new Call(Location().introduce(),constants().ids.forall,{al}); forall->decl(env.model->matchFn(env,forall,false)); forall->type(forall->decl()->rtype(env,{al},false)); e_then.back().push_back(forall); } } { if (eq_branches[ite->size()].size()==0) { e_else.push_back(ite->e_else()); } else if (other_branches[ite->size()].size()==0) { e_else.push_back(constants().lit_true); } else if (other_branches[ite->size()].size()==1) { e_else.push_back(other_branches[ite->size()][0]); } else { GCLock lock; ArrayLit* al = new ArrayLit(Location().introduce(), other_branches[ite->size()]); al->type(Type::varbool(1)); Call* forall = new Call(Location().introduce(),constants().ids.forall,{al}); forall->decl(env.model->matchFn(env,forall,false)); forall->type(forall->decl()->rtype(env,{al},false)); e_else.push_back(forall); } } } } else { noOtherBranches = false; results.push_back(r); e_then.push_back(std::vector()); for (int i=0; isize(); i++) { e_then.back().push_back(ite->e_then(i)); } e_else.push_back(ite->e_else()); } allBranchesPar.resize(results.size()); r_bounds_valid_int.resize(results.size()); r_bounds_int.resize(results.size()); r_bounds_valid_float.resize(results.size()); r_bounds_float.resize(results.size()); r_bounds_valid_set.resize(results.size()); r_bounds_set.resize(results.size()); defined.resize(results.size()); branches.resize(results.size()); for (unsigned int i=0; isize() && !foundTrueBranch; i++) { bool cond = true; EE e_if; if (ite->e_if(i)->isa() && ite->e_if(i)->cast()->id()=="mzn_in_root_context") { e_if = EE(constants().boollit(ctx.b==C_ROOT), constants().lit_true); } else { Ctx cmix_not_negated; cmix_not_negated.b = C_MIX; cmix_not_negated.i = C_MIX; e_if = flat_exp(env,cmix_not_negated,ite->e_if(i),NULL,constants().var_true); } if (e_if.r()->type()==Type::parbool()) { { GCLock lock; cond = eval_bool(env,e_if.r()); } if (cond) { if (allConditionsPar) { // no var conditions before this one, so we can simply emit // the then branch return flat_exp(env,ctx,ite->e_then(i),r,b); } // had var conditions, so we have to take them into account // and emit new conditional clause // add another condition and definedness variable conditions.push_back(constants().lit_true); for (unsigned int j=0; jtype().isvar()) { allBranchesPar[j] = false; } } foundTrueBranch = true; } else { conditions.push_back(constants().lit_false); for (unsigned int j=0; jtype())); } } } else { allConditionsPar = false; // add current condition and definedness variable conditions.push_back(e_if.r); for (unsigned int j=0; jtype().isvar()) { allBranchesPar[j] = false; } } } // update bounds if (cond) { for (unsigned int j=0; jtype().isint()) { GCLock lock; IntBounds ib_then = compute_int_bounds(env,branches[j][i]()); if (ib_then.valid) r_bounds_int[j].push_back(ib_then); r_bounds_valid_int[j] = r_bounds_valid_int[j] && ib_then.valid; } else if (r_bounds_valid_set[j] && e_then[j][i]()->type().isintset()) { GCLock lock; IntSetVal* isv = compute_intset_bounds(env, branches[j][i]()); if (isv) r_bounds_set[j].push_back(isv); r_bounds_valid_set[j] = r_bounds_valid_set[j] && isv; } else if (r_bounds_valid_float[j] && e_then[j][i]()->type().isfloat()) { GCLock lock; FloatBounds fb_then = compute_float_bounds(env, branches[j][i]()); if (fb_then.valid) r_bounds_float[j].push_back(fb_then); r_bounds_valid_float[j] = r_bounds_valid_float[j] && fb_then.valid; } } } } if (allConditionsPar) { // no var condition, and all par conditions were false, // so simply emit else branch return flat_exp(env,ctx,ite->e_else(),r,b); } for (unsigned int j=0; jtype(),NULL); results[j] = newVarDecl(env, Ctx(), ti, NULL, NULL, NULL); } } if (conditions.back()() != constants().lit_true) { // The last condition wasn't fixed to true, we need to look at the else branch conditions.push_back(constants().lit_true); for (unsigned int j=0; jtype().isvar()) { allBranchesPar[j] = false; } if (r_bounds_valid_int[j] && e_else[j]()->type().isint()) { GCLock lock; IntBounds ib_else = compute_int_bounds(env,eelse.r()); if (ib_else.valid) r_bounds_int[j].push_back(ib_else); r_bounds_valid_int[j] = r_bounds_valid_int[j] && ib_else.valid; } else if (r_bounds_valid_set[j] && e_else[j]()->type().isintset()) { GCLock lock; IntSetVal* isv = compute_intset_bounds(env, eelse.r()); if (isv) r_bounds_set[j].push_back(isv); r_bounds_valid_set[j] = r_bounds_valid_set[j] && isv; } else if (r_bounds_valid_float[j] && e_else[j]()->type().isfloat()) { GCLock lock; FloatBounds fb_else = compute_float_bounds(env, eelse.r()); if (fb_else.valid) r_bounds_float[j].push_back(fb_else); r_bounds_valid_float[j] = r_bounds_valid_float[j] && fb_else.valid; } } } // update domain of result variable with bounds from all branches for (unsigned int j=0; jtype().isint()) { IntVal lb = IntVal::infinity(); IntVal ub = -IntVal::infinity(); for (unsigned int i=0; iti()->domain()) { IntSetVal* isv = eval_intset(env, nr->ti()->domain()); Ranges::Const ite_r(lb,ub); IntSetRanges isv_r(isv); Ranges::Inter, IntSetRanges> inter(ite_r,isv_r); IntSetVal* isv_new = IntSetVal::ai(inter); if (isv_new->card()!=isv->card()) { SetLit* r_dom = new SetLit(Location().introduce(), isv_new); nr->ti()->domain(r_dom); } } else { SetLit* r_dom = new SetLit(Location().introduce(), IntSetVal::a(lb,ub)); nr->ti()->domain(r_dom); nr->ti()->setComputedDomain(true); } } else if (r_bounds_valid_set[j] && ite->type().isintset()) { IntSetVal* isv_branches = IntSetVal::a(); for (unsigned int i=0; i u(i0,i1); isv_branches = IntSetVal::ai(u); } if (nr->ti()->domain()) { IntSetVal* isv = eval_intset(env, nr->ti()->domain()); IntSetRanges isv_r(isv); IntSetRanges isv_branches_r(isv_branches); Ranges::Inter inter(isv_branches_r,isv_r); IntSetVal* isv_new = IntSetVal::ai(inter); if (isv_new->card()!=isv->card()) { SetLit* r_dom = new SetLit(Location().introduce(), isv_new); nr->ti()->domain(r_dom); } } else { SetLit* r_dom = new SetLit(Location().introduce(), isv_branches); nr->ti()->domain(r_dom); nr->ti()->setComputedDomain(true); } } else if (r_bounds_valid_float[j] && ite->type().isfloat()) { FloatVal lb = FloatVal::infinity(); FloatVal ub = -FloatVal::infinity(); for (unsigned int i=0; iti()->domain()) { FloatSetVal* isv = eval_floatset(env, nr->ti()->domain()); Ranges::Const ite_r(lb,ub); FloatSetRanges isv_r(isv); Ranges::Inter, FloatSetRanges> inter(ite_r,isv_r); FloatSetVal* fsv_new = FloatSetVal::ai(inter); SetLit* r_dom = new SetLit(Location().introduce(), fsv_new); nr->ti()->domain(r_dom); } else { SetLit* r_dom = new SetLit(Location().introduce(), FloatSetVal::a(lb,ub)); nr->ti()->domain(r_dom); nr->ti()->setComputedDomain(true); } } } // Create ite predicate calls GCLock lock; ArrayLit* al_cond = new ArrayLit(Location().introduce(), conditions); al_cond->type(Type::varbool(1)); for (unsigned int j=0; jtype(); branches_t.dim(1); branches_t.ti(allBranchesPar[j] ? Type::TI_PAR : Type::TI_VAR); al_branches->type(branches_t); Call* ite_pred = new Call(ite->loc().introduce(),ASTString("if_then_else"),{al_cond,al_branches,results[j]->id()}); ite_pred->decl(env.model->matchFn(env, ite_pred, false)); ite_pred->type(Type::varbool()); (void) flat_exp(env, Ctx(), ite_pred, constants().var_true, constants().var_true); } EE ret; if (noOtherBranches) { ret.r = constants().var_true->id(); } else { ret.r = results.back()->id(); } if (allDefined) { bind(env, Ctx(), b, constants().lit_true); ret.b = constants().lit_true; } else { // Otherwise, constraint linking conditions, b and the definedness variables if (b==NULL) { CallStackItem _csi(env, new StringLit(Location().introduce(), "b")); b = newVarDecl(env, Ctx(), new TypeInst(Location().introduce(),Type::varbool()), NULL, NULL, NULL); } ret.b = b->id(); std::vector defined_conjunctions(ite->size()+1); for (unsigned int i=0; isize()+1; i++) { std::vector def_i; for (unsigned int j=0; ji); if (defined[j][i]() != constants().lit_true) { def_i.push_back(defined[j][i]()); } } if (def_i.size()==0) { defined_conjunctions[i] = constants().lit_true; } else if (def_i.size()==1) { defined_conjunctions[i] = def_i[0]; } else { ArrayLit* al = new ArrayLit(Location().introduce(), def_i); al->type(Type::varbool(1)); Call* forall = new Call(Location().introduce(),constants().ids.forall,{al}); forall->decl(env.model->matchFn(env,forall,false)); forall->type(forall->decl()->rtype(env,{al},false)); defined_conjunctions[i] = forall; } } ArrayLit* al_defined = new ArrayLit(Location().introduce(), defined_conjunctions); al_defined->type(Type::varbool(1)); Call* ite_defined_pred = new Call(ite->loc().introduce(),ASTString("if_then_else_partiality"),{al_cond,al_defined,b->id()}); ite_defined_pred->decl(env.model->matchFn(env, ite_defined_pred, false)); ite_defined_pred->type(Type::varbool()); (void) flat_exp(env, Ctx(), ite_defined_pred, constants().var_true, constants().var_true); } return ret; } } libminizinc-2.4.2/lib/flatten/flatten_let.cpp000066400000000000000000000106701360574160400212500ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include namespace MiniZinc { EE flatten_let(EnvI& env,Ctx ctx, Expression* e, VarDecl* r, VarDecl* b) { CallStackItem _csi(env,e); EE ret; Let* let = e->cast(); GC::mark(); std::vector cs; std::vector flatmap; let->pushbindings(); for (unsigned int i=0; ilet().size(); i++) { Expression* le = let->let()[i]; if (VarDecl* vd = le->dyn_cast()) { Expression* let_e = NULL; if (vd->e()) { Ctx nctx = ctx; nctx.neg = false; if (vd->e()->type().bt()==Type::BT_BOOL) nctx.b = C_MIX; EE ee = flat_exp(env,nctx,vd->e(),NULL,NULL); let_e = ee.r(); cs.push_back(ee); if (vd->ti()->domain() != NULL) { GCLock lock; std::vector domargs(2); domargs[0] = ee.r(); if (vd->ti()->type().isfloat()) { FloatSetVal* fsv = eval_floatset(env, vd->ti()->domain()); if (fsv->size()==1) { domargs[1] = FloatLit::a(fsv->min()); domargs.push_back(FloatLit::a(fsv->max())); } else { domargs[1] = vd->ti()->domain(); } } else { domargs[1] = vd->ti()->domain(); } Call* c = new Call(vd->ti()->loc().introduce(),"var_dom",domargs); c->type(Type::varbool()); c->decl(env.model->matchFn(env,c,false)); if (c->decl()==NULL) throw InternalError("no matching declaration found for var_dom"); VarDecl* b_b = (nctx.b==C_ROOT && b==constants().var_true) ? b : NULL; VarDecl* r_r = (nctx.b==C_ROOT && b==constants().var_true) ? b : NULL; ee = flat_exp(env, nctx, c, r_r, b_b); cs.push_back(ee); ee.b = ee.r; cs.push_back(ee); } if (vd->type().dim() > 0) { checkIndexSets(env, vd, let_e); } } else { if ((ctx.b==C_NEG || ctx.b==C_MIX) && !vd->ann().contains(constants().ann.promise_total)) { CallStackItem csi_vd(env, vd); throw FlatteningError(env,vd->loc(), "free variable in non-positive context"); } CallStackItem csi_vd(env, vd); GCLock lock; TypeInst* ti = eval_typeinst(env,vd); VarDecl* nvd = newVarDecl(env, ctx, ti, NULL, vd, NULL); let_e = nvd->id(); } vd->e(let_e); flatmap.push_back(vd->flat()); if (Id* id = Expression::dyn_cast(let_e)) { vd->flat(id->decl()); } else { vd->flat(vd); } } else { if (ctx.b==C_ROOT || le->ann().contains(constants().ann.promise_total)) { (void) flat_exp(env,Ctx(),le,constants().var_true,constants().var_true); } else { EE ee = flat_exp(env,ctx,le,NULL,constants().var_true); ee.b = ee.r; cs.push_back(ee); } } } if (r==constants().var_true && ctx.b==C_ROOT && !ctx.neg) { ret.b = bind(env,Ctx(),b,constants().lit_true); (void) flat_exp(env,ctx,let->in(),r,b); ret.r = conj(env,r,Ctx(),cs); } else { Ctx nctx = ctx; nctx.neg = false; VarDecl* bb = b; for (EE& ee : cs) { if (ee.b() != constants().lit_true) { bb = NULL; break; } } EE ee = flat_exp(env,nctx,let->in(),NULL,bb); if (let->type().isbool() && !let->type().isopt()) { ee.b = ee.r; cs.push_back(ee); ret.r = conj(env,r,ctx,cs); ret.b = bind(env,Ctx(),b,constants().lit_true); } else { cs.push_back(ee); ret.r = bind(env,Ctx(),r,ee.r()); ret.b = conj(env,b,Ctx(),cs); } } let->popbindings(); // Restore previous mapping for (unsigned int i=0; ilet().size(); i++) { if (VarDecl* vd = let->let()[i]->dyn_cast()) { vd->flat(Expression::cast(flatmap.back()())); flatmap.pop_back(); } } return ret; } } libminizinc-2.4.2/lib/flatten/flatten_par.cpp000066400000000000000000000064351360574160400212520ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include namespace MiniZinc { EE flatten_par(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b) { EE ret; if (e->type().cv()) { KeepAlive ka = flat_cv_exp(env,ctx,e); ret.r = bind(env,ctx,r,ka()); ret.b = bind(env,Ctx(),b,constants().lit_true); return ret; } if (e->type().dim() > 0) { EnvI::CSEMap::iterator it; Id* id = e->dyn_cast(); if (id && (id->decl()->flat()==NULL || id->decl()->toplevel())) { VarDecl* vd = id->decl()->flat(); if (vd==NULL) { vd = flat_exp(env,Ctx(),id->decl(),NULL,constants().var_true).r()->cast()->decl(); id->decl()->flat(vd); ArrayLit* al = follow_id(vd->id())->cast(); if (al->size()==0) { if (r==NULL) ret.r = al; else ret.r = bind(env,ctx,r,al); ret.b = bind(env,Ctx(),b,constants().lit_true); return ret; } } ret.r = bind(env,ctx,r,e->cast()->decl()->flat()->id()); ret.b = bind(env,Ctx(),b,constants().lit_true); return ret; } else if ( (it = env.cse_map_find(e)) != env.cse_map_end()) { ret.r = bind(env,ctx,r,it->second.r()->cast()->id()); ret.b = bind(env,Ctx(),b,constants().lit_true); return ret; } else { GCLock lock; ArrayLit* al = follow_id(eval_par(env,e))->cast(); if (al->size()==0 || (r && r->e()==NULL)) { if (r==NULL) ret.r = al; else ret.r = bind(env,ctx,r,al); ret.b = bind(env,Ctx(),b,constants().lit_true); return ret; } if ( (it = env.cse_map_find(al)) != env.cse_map_end()) { ret.r = bind(env,ctx,r,it->second.r()->cast()->id()); ret.b = bind(env,Ctx(),b,constants().lit_true); return ret; } std::vector ranges(al->dims()); for (unsigned int i=0; iloc(), Type(), new SetLit(Location().introduce(),IntSetVal::a(al->min(i),al->max(i)))); } ASTExprVec ranges_v(ranges); assert(!al->type().isbot()); TypeInst* ti = new TypeInst(e->loc(),al->type(),ranges_v,NULL); VarDecl* vd = newVarDecl(env, ctx, ti, NULL, NULL, al); EE ee(vd,NULL); env.cse_map_insert(al,ee); env.cse_map_insert(vd->e(),ee); ret.r = bind(env,ctx,r,vd->id()); ret.b = bind(env,Ctx(),b,constants().lit_true); return ret; } } GCLock lock; try { ret.r = bind(env,ctx,r,eval_par(env,e)); ret.b = bind(env,Ctx(),b,constants().lit_true); } catch (ResultUndefinedError&) { ret.r = createDummyValue(env, e->type()); ret.b = bind(env,Ctx(),b,constants().lit_false); } return ret; } } libminizinc-2.4.2/lib/flatten/flatten_setlit.cpp000066400000000000000000000035121360574160400217650ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include namespace MiniZinc { EE flatten_setlit(EnvI& env,Ctx ctx, Expression* e, VarDecl* r, VarDecl* b) { CallStackItem _csi(env,e); EE ret; SetLit* sl = e->cast(); assert(sl->isv()==NULL && sl->fsv()==NULL); std::vector elems_ee(sl->v().size()); for (unsigned int i=sl->v().size(); i--;) elems_ee[i] = flat_exp(env,ctx,sl->v()[i],NULL,NULL); std::vector elems(elems_ee.size()); bool allPar = true; for (unsigned int i=static_cast(elems.size()); i--;) { elems[i] = elems_ee[i].r(); allPar = allPar && elems[i]->type().ispar(); } ret.b = conj(env,b,Ctx(),elems_ee); if (allPar) { GCLock lock; Expression* ee = eval_par(env,e); ret.r = bind(env,Ctx(),r,ee); } else { GCLock lock; ArrayLit* al = new ArrayLit(sl->loc(),elems); al->type(Type::varint(1)); std::vector args(1); args[0] = al; Call* cc = new Call(sl->loc().introduce(), "array2set", args); cc->type(Type::varsetint()); FunctionI* fi = env.model->matchFn(env, cc->id(), args, false); if (fi==NULL) { throw FlatteningError(env,cc->loc(), "cannot find matching declaration"); } assert(fi); assert(env.isSubtype(fi->rtype(env, args, false),cc->type(),false)); cc->decl(fi); EE ee = flat_exp(env, Ctx(), cc, NULL, constants().var_true); ret.r = bind(env,Ctx(),r,ee.r()); } return ret; } } libminizinc-2.4.2/lib/flatten/flatten_unop.cpp000066400000000000000000000027401360574160400214440ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include namespace MiniZinc { EE flatten_unop(EnvI& env,Ctx ctx, Expression* e, VarDecl* r, VarDecl* b) { CallStackItem _csi(env,e); EE ret; UnOp* uo = e->cast(); switch (uo->op()) { case UOT_NOT: { Ctx nctx = ctx; nctx.b = -nctx.b; nctx.neg = !nctx.neg; ret = flat_exp(env,nctx,uo->e(),r,b); } break; case UOT_PLUS: ret = flat_exp(env,ctx,uo->e(),r,b); break; case UOT_MINUS: { GC::lock(); if (UnOp* uo_inner = uo->e()->dyn_cast()) { if (uo_inner->op()==UOT_MINUS) { ret = flat_exp(env,ctx,uo_inner->e(),r,b); break; } } Expression* zero; if (uo->e()->type().bt()==Type::BT_INT) zero = IntLit::a(0); else zero = FloatLit::a(0.0); BinOp* bo = new BinOp(Location().introduce(),zero,BOT_MINUS,uo->e()); bo->type(uo->type()); KeepAlive ka(bo); GC::unlock(); ret = flat_exp(env,ctx,ka(),r,b); } break; default: break; } return ret; } } libminizinc-2.4.2/lib/flatten/flatten_vardecl.cpp000066400000000000000000000037141360574160400221050ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include namespace MiniZinc { EE flatten_vardecl(EnvI& env,Ctx ctx, Expression* e, VarDecl* r, VarDecl* b) { CallStackItem _csi(env,e); EE ret; GCLock lock; if (ctx.b != C_ROOT) throw FlatteningError(env,e->loc(), "not in root context"); VarDecl* v = e->cast(); VarDecl* it = v->flat(); if (it==NULL) { TypeInst* ti = eval_typeinst(env,v); bool reuseVarId = v->type().isann() || ( v->toplevel() && v->id()->idn()==-1 && v->id()->v().c_str()[0]!='\'' && v->id()->v().c_str()[0]!='_' ); VarDecl* vd = newVarDecl(env, ctx, ti, reuseVarId ? v->id() : NULL, v, NULL); v->flat(vd); Ctx nctx; if (v->e() && v->e()->type().bt() == Type::BT_BOOL) nctx.b = C_MIX; if (v->e()) { (void) flat_exp(env,nctx,v->e(),vd,constants().var_true); if (v->e()->type().dim() > 0) { Expression* ee = follow_id_to_decl(vd->e()); if (ee->isa()) ee = ee->cast()->e(); assert(ee && ee->isa()); ArrayLit* al = ee->cast(); if (vd->ti()->domain()) { for (unsigned int i=0; isize(); i++) { if (Id* ali_id = (*al)[i]->dyn_cast()) { if (ali_id->decl()->ti()->domain()==NULL) { ali_id->decl()->ti()->domain(vd->ti()->domain()); } } } } } } ret.r = bind(env,Ctx(),r,vd->id()); } else { ret.r = bind(env,Ctx(),r,it); } ret.b = bind(env,Ctx(),b,constants().lit_true); return ret; } } libminizinc-2.4.2/lib/flattener.cpp000066400000000000000000001010561360574160400172750ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was ! distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* A basic mzn2fzn wrapper, can be used as a plugin */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #ifdef HAS_GECODE #include #endif using namespace std; using namespace MiniZinc; void Flattener::printVersion(ostream& os) { os << "MiniZinc to FlatZinc converter, version " << MZN_VERSION_MAJOR << "." << MZN_VERSION_MINOR << "." << MZN_VERSION_PATCH; if (!std::string(MZN_BUILD_REF).empty()) { os << ", build " << MZN_BUILD_REF; } os << std::endl; os << "Copyright (C) 2014-" << string(__DATE__).substr(7, 4) << " Monash University, NICTA, Data61" << std::endl; } void Flattener::printHelp(ostream& os) { os << std::endl << "Flattener input options:" << std::endl << " --ignore-stdlib\n Ignore the standard libraries stdlib.mzn and builtins.mzn" << std::endl << " --instance-check-only\n Check the model instance (including data) for errors, but do not\n convert to FlatZinc." << std::endl << " -e, --model-check-only\n Check the model (without requiring data) for errors, but do not\n convert to FlatZinc." << std::endl << " --model-interface-only\n Only extract parameters and output variables." << std::endl << " --model-types-only\n Only output variable (enum) type information." << std::endl << " --no-optimize\n Do not optimize the FlatZinc" << std::endl << " --no-chain-compression\n Do not simplify chains of implication constraints." << std::endl << " -d , --data \n File named contains data used by the model." << std::endl << " -D , --cmdline-data \n Include the given data assignment in the model." << std::endl << " --stdlib-dir \n Path to MiniZinc standard library directory" << std::endl << " -G , --globals-dir , --mzn-globals-dir \n Search for included globals in /." << std::endl << " -, --input-from-stdin\n Read problem from standard input" << std::endl << " -I , --search-dir \n Additionally search for included files in ." << std::endl << " -D \"fMIPdomains=true\"\n Switch on MIPDomain Unification" << std::endl << " --MIPDMaxIntvEE \n MIPD: max integer domain subinterval length to enforce equality encoding, default " << opt_MIPDmaxIntvEE << std::endl << " --MIPDMaxDensEE \n MIPD: max domain cardinality to N subintervals ratio\n to enforce equality encoding, default " << opt_MIPDmaxDensEE << ", either condition triggers" << std::endl << " --only-range-domains\n When no MIPdomains: all domains contiguous, holes replaced by inequalities" << std::endl << " --allow-multiple-assignments\n Allow multiple assignments to the same variable (e.g. in dzn)" << std::endl << " --no-half-reifications\n Only use fully reified constraints, even when a half reified constraint is defined." << std::endl << " --compile-solution-checker .mzc.mzn\n Compile solution checker model" << std::endl << std::endl << "Flattener two-pass options:" << std::endl << " --two-pass\n Flatten twice to make better flattening decisions for the target" << std::endl #ifdef HAS_GECODE << " --use-gecode\n Perform root-node-propagation with Gecode (adds --two-pass)" << std::endl << " --shave\n Probe bounds of all variables at the root node (adds --use-gecode)" << std::endl << " --sac\n Probe values of all variables at the root node (adds --use-gecode)" << std::endl << " --pre-passes \n Number of times to apply shave/sac pass (0 = fixed-point, 1 = default)" << std::endl #endif << " -O\n Two-pass optimisation levels:" << std::endl << " -O0: Disable optimize (--no-optimize) -O1: Single pass (default)" << std::endl << " -O2: Same as: --two-pass" #ifdef HAS_GECODE << " -O3: Same as: --use-gecode" << std::endl << " -O4: Same as: --shave -O5: Same as: --sac" << std::endl #else << "\n -O3,4,5: Disabled [Requires MiniZinc with built-in Gecode support]" << std::endl #endif << " -g\n Debug mode: Forces -O0 and records all domain changes as constraints instead of applying them" << std::endl << std::endl; os << "Flattener output options:" << std::endl << " --no-output-ozn, -O-\n Do not output ozn file" << std::endl << " --output-base \n Base name for output files" << std::endl << ( fOutputByDefault ? " -o , --fzn , --output-to-file , --output-fzn-to-file \n" : " --fzn , --output-fzn-to-file \n" ) << " Filename for generated FlatZinc output" << std::endl << " -O, --ozn, --output-ozn-to-file \n Filename for model output specification (-O- for none)" << std::endl << " --keep-paths\n Don't remove path annotations from FlatZinc" << std::endl << " --output-paths\n Output a symbol table (.paths file)" << std::endl << " --output-paths-to-file \n Output a symbol table (.paths file) to " << std::endl << " --output-detailed-timing\n Output detailed profiling information of compilation time" << std::endl << " --output-to-stdout, --output-fzn-to-stdout\n Print generated FlatZinc to standard output" << std::endl << " --output-ozn-to-stdout\n Print model output specification to standard output" << std::endl << " --output-paths-to-stdout\n Output symbol table to standard output" << std::endl << " --output-mode \n Create output according to output item (default), or output compatible\n with dzn or json format" << std::endl << " --output-objective\n Print value of objective function in dzn or json output" << std::endl << " --output-output-item\n Print the output item as a string in the dzn or json output" << std::endl << " -Werror\n Turn warnings into errors" << std::endl ; } bool Flattener::processOption(int& i, std::vector& argv) { CLOParser cop( i, argv ); string buffer; if ( cop.getOption( "-I --search-dir", &buffer ) ) { includePaths.push_back(buffer+string("/")); } else if ( cop.getOption( "--ignore-stdlib" ) ) { flag_ignoreStdlib = true; } else if ( cop.getOption( "--no-typecheck") ) { flag_typecheck = false; } else if ( cop.getOption( "--instance-check-only") ) { flag_instance_check_only = true; } else if ( cop.getOption( "-e --model-check-only") ) { flag_model_check_only = true; } else if ( cop.getOption( "--model-interface-only") ) { flag_model_interface_only = true; } else if ( cop.getOption( "--model-types-only") ) { flag_model_types_only = true; } else if ( cop.getOption( "-v --verbose") ) { flag_verbose = true; } else if (string(argv[i])==string("--newfzn")) { flag_newfzn = true; } else if ( cop.getOption( "--no-optimize --no-optimise") ) { flag_optimize = false; } else if ( cop.getOption( "--no-chain-compression") ) { flag_chain_compression = false; } else if ( cop.getOption( "--no-output-ozn -O-") ) { flag_no_output_ozn = true; } else if ( cop.getOption( "--output-base", &flag_output_base ) ) { } else if ( cop.getOption( fOutputByDefault ? "-o --fzn --output-to-file --output-fzn-to-file" : "--fzn --output-fzn-to-file", &flag_output_fzn) ) { } else if ( cop.getOption( "--output-paths-to-file", &flag_output_paths) ) { fopts.collect_mzn_paths = true; } else if ( cop.getOption( "--output-paths") ) { fopts.collect_mzn_paths = true; } else if ( cop.getOption( "--output-to-stdout --output-fzn-to-stdout" ) ) { flag_output_fzn_stdout = true; } else if ( cop.getOption( "--output-ozn-to-stdout" ) ) { flag_output_ozn_stdout = true; } else if ( cop.getOption( "--output-paths-to-stdout" ) ) { fopts.collect_mzn_paths = true; flag_output_paths_stdout = true; } else if ( cop.getOption( "--output-detailed-timing" ) ) { fopts.detailedTiming = true; } else if ( cop.getOption( "--output-mode", &buffer ) ) { if (buffer == "dzn") { flag_output_mode = FlatteningOptions::OUTPUT_DZN; } else if (buffer == "json") { flag_output_mode = FlatteningOptions::OUTPUT_JSON; } else if (buffer == "item") { flag_output_mode = FlatteningOptions::OUTPUT_ITEM; } else { return false; } } else if ( cop.getOption( "--output-objective" ) ) { flag_output_objective = true; } else if ( cop.getOption( "--output-output-item" ) ) { flag_output_output_item = true; } else if ( cop.getOption( "- --input-from-stdin" ) ) { flag_stdinInput = true; } else if ( cop.getOption( "-d --data", &buffer ) ) { if ( buffer.length()<=4 || buffer.substr(buffer.length()-4,string::npos) != ".dzn") return false; datafiles.push_back(buffer); } else if ( cop.getOption( "--stdlib-dir", &std_lib_dir ) ) { } else if ( cop.getOption( "-G --globals-dir --mzn-globals-dir", &globals_dir ) ) { } else if ( cop.getOption( "-D --cmdline-data", &buffer)) { datafiles.push_back("cmd:/"+buffer); } else if ( cop.getOption( "--allow-unbounded-vars" ) ) { flag_allow_unbounded_vars = true; } else if ( cop.getOption( "--only-range-domains" ) ) { flag_only_range_domains = true; } else if ( cop.getOption( "--no-MIPdomains" ) ) { // internal flag_noMIPdomains = true; } else if ( cop.getOption( "--MIPDMaxIntvEE", &opt_MIPDmaxIntvEE ) ) { } else if ( cop.getOption( "--MIPDMaxDensEE", &opt_MIPDmaxDensEE ) ) { } else if ( cop.getOption( "-Werror" ) ) { flag_werror = true; } else if (string(argv[i])=="--use-gecode") { #ifdef HAS_GECODE flag_two_pass = true; flag_gecode = true; #else log << "warning: Gecode not available. Ignoring '--use-gecode'\n"; #endif } else if (string(argv[i])=="--sac") { #ifdef HAS_GECODE flag_two_pass = true; flag_gecode = true; flag_sac = true; #else log << "warning: Gecode not available. Ignoring '--sac'\n"; #endif } else if (string(argv[i])=="--shave") { #ifdef HAS_GECODE flag_two_pass = true; flag_gecode = true; flag_shave = true; #else log << "warning: Gecode not available. Ignoring '--shave'\n"; #endif } else if (string(argv[i])=="--two-pass") { flag_two_pass = true; } else if (string(argv[i])=="--npass") { i++; if (i==argv.size()) return false; log << "warning: --npass option is deprecated --two-pass\n"; int passes = atoi(argv[i].c_str()); if(passes == 1) flag_two_pass = false; else if(passes == 2) flag_two_pass = true; } else if (string(argv[i])=="--pre-passes") { i++; if (i==argv.size()) return false; int passes = atoi(argv[i].c_str()); if(passes >= 0) { flag_pre_passes = static_cast(passes); } } else if (string(argv[i])=="-O0") { flag_optimize = false; } else if (string(argv[i])=="-O1") { // Default settings } else if (string(argv[i])=="-O2") { flag_two_pass = true; #ifdef HAS_GECODE } else if (string(argv[i])=="-O3") { flag_two_pass = true; flag_gecode = true; } else if (string(argv[i])=="-O4") { flag_two_pass = true; flag_gecode = true; flag_shave = true; } else if (string(argv[i])=="-O5") { flag_two_pass = true; flag_gecode = true; flag_sac = true; #else } else if (string(argv[i])=="-O3" || string(argv[i])=="-O4" || string(argv[i])=="-O5") { log << "% Warning: This compiler does not have Gecode builtin, cannot process -O3,-O4,-O5.\n"; return false; #endif // ozn options must be after the -O optimisation options } else if ( cop.getOption( "-O --ozn --output-ozn-to-file", &flag_output_ozn) ) { } else if (string(argv[i])=="-g") { flag_optimize = false; flag_two_pass = false; flag_gecode = false; flag_shave = false; flag_sac = false; fopts.record_domain_changes = true; } else if (string(argv[i])=="--keep-paths") { flag_keep_mzn_paths = true; fopts.collect_mzn_paths = true; } else if (string(argv[i])=="--only-toplevel-presolve") { fopts.only_toplevel_paths = true; } else if ( cop.getOption( "--allow-multiple-assignments" ) ) { flag_allow_multi_assign = true; } else if ( cop.getOption( "--no-half-reifications" ) ) { fopts.enable_imp = false; } else if (string(argv[i])=="--input-is-flatzinc") { is_flatzinc = true; } else if ( cop.getOption( "--compile-solution-checker", &buffer) ) { if (buffer.length()>=8 && buffer.substr(buffer.length()-8,string::npos) == ".mzc.mzn") { flag_compile_solution_check_model = true; flag_model_check_only = true; filenames.push_back(buffer); } else { log << "Error: solution checker model must have extension .mzc.mzn" << std::endl; return false; } } else { std::string input_file(argv[i]); if (input_file.length()<=4) { return false; } size_t last_dot = input_file.find_last_of('.'); if (last_dot == string::npos) { return false; } std::string extension = input_file.substr(last_dot,string::npos); if ( extension == ".mzc" || (input_file.length()>=8 && input_file.substr(input_file.length()-8,string::npos) == ".mzc.mzn") ) { flag_solution_check_model = input_file; } else if (extension == ".mzn" || extension == ".fzn") { if ( extension == ".fzn" ) { is_flatzinc = true; if ( fOutputByDefault ) // mzn2fzn mode return false; } filenames.push_back(input_file); } else if (extension == ".dzn" || extension == ".json") { datafiles.push_back(input_file); } else { if ( fOutputByDefault ) log << "Error: cannot handle file extension " << extension << "." << std::endl; return false; } } return true; } Flattener::Flattener(std::ostream& os_, std::ostream& log_, const std::string& stdlibDir) : os(os_), log(log_), std_lib_dir(stdlibDir) {} Flattener::~Flattener() { if (pEnv.get()) { // ??? TODO if(is_flatzinc) { pEnv->swap(); } } } Env* Flattener::multiPassFlatten(const vector >& passes) { Env& e = *getEnv(); Env* pre_env = &e; size_t npasses = passes.size(); pre_env->envi().final_pass_no = static_cast(npasses); Timer starttime; bool verbose = false; for(unsigned int i=0; ienvi().current_pass_no = i; if(verbose) log << "Start pass " << i << ":\n"; Env* out_env = passes[i]->run(pre_env,log); if(out_env == nullptr) return nullptr; if(pre_env != &e && pre_env != out_env) { delete pre_env; } pre_env = out_env; if(verbose) log << "Finish pass " << i << ": " << starttime.stoptime() << "\n"; } return pre_env; } class FlattenTimeout { public: FlattenTimeout(unsigned long long int t) { GC::setTimeout(t); } ~FlattenTimeout(void) { GC::setTimeout(0); } }; void Flattener::flatten(const std::string& modelString, const std::string& modelName) { FlattenTimeout flatten_timeout(fopts.timeout); Timer flatten_time; starttime.reset(); if (flag_verbose) printVersion(log); if (filenames.empty() && !flag_solution_check_model.empty()) { // Compile solution check model as if it were a normal model filenames.push_back(flag_solution_check_model); flag_solution_check_model = ""; } if ( filenames.empty() && !flag_stdinInput && modelString.empty() ) { throw Error( "Error: no model file given." ); } if (std_lib_dir=="") { throw Error("Error: unknown minizinc standard library directory.\n" "Specify --stdlib-dir on the command line or set the\n" "MZN_STDLIB_DIR environment variable."); } if (globals_dir != "") { includePaths.insert(includePaths.begin(), std_lib_dir+"/"+globals_dir+"/"); } includePaths.push_back(std_lib_dir+"/std/"); for (unsigned int i=0; i= 4 && flag_solution_check_model.substr(flag_solution_check_model.size()-4)==".mzc"; std::vector smm_model({flag_solution_check_model}); Model* smm = parse(*env, smm_model, datafiles, "", "", includePaths, flag_ignoreStdlib, false, flag_verbose, errstream); if (flag_verbose) log << " done parsing (" << starttime.stoptime() << ")" << std::endl; if (smm) { log << errstream.str(); errstream.str(""); std::ostringstream smm_oss; Printer p(smm_oss,0,false); p.print(smm); Env smm_env(smm); GCLock lock; vector typeErrors; try { MiniZinc::typecheck(smm_env, smm, typeErrors, true, false, true); if (typeErrors.size() > 0) { if (!isCompressedChecker) { for (unsigned int i=0; isize(); i++) { if (VarDeclI* vdi = (*smm)[i]->dyn_cast()) { if (vdi->e()->e()==NULL) env->envi().checkVars.push_back(vdi->e()); } } smm->compact(); std::string smm_compressed = FileUtils::encodeBase64(FileUtils::deflateString(smm_oss.str())); TypeInst* ti = new TypeInst(Location().introduce(),Type::parstring(),NULL); VarDecl* checkString = new VarDecl(Location().introduce(),ti,ASTString("_mzn_solution_checker"),new StringLit(Location().introduce(),smm_compressed)); VarDeclI* checkStringI = new VarDeclI(Location().introduce(), checkString); env->output()->addItem(checkStringI); } catch (TypeError& e) { if (isCompressedChecker) { log << "Warning: type error in solution checker model\n"; } else { throw; } } } else { if (isCompressedChecker) { log << "Warning: syntax error in solution checker model\n"; } else { log << errstream.str(); throw Error("parse error"); } } } if (flag_compile_solution_check_model) { if (!modelString.empty()) { throw Error("Cannot compile solution checker model with additional model inputs."); } if (flag_stdinInput) { throw Error("Cannot compile solution checker model with additional model from standard input."); } if (filenames.size() != 1) { throw Error("Cannot compile solution checker model with more than one model given."); } } if (!flag_solution_check_model.empty() && filenames.size()==0) { throw Error("Cannot run solution checker without model."); } std::string modelText = modelString; if (flag_stdinInput) { std::string input = std::string(istreambuf_iterator(std::cin), istreambuf_iterator()); modelText += input; } if (flag_verbose) { log << "Parsing file(s) "; for ( int i=0; imodel(m); if (flag_typecheck) { if (flag_verbose) log << " done parsing (" << starttime.stoptime() << ")" << std::endl; if (flag_instance_check_only || flag_model_check_only || flag_model_interface_only || flag_model_types_only ) { std::ostringstream compiledSolutionCheckModel; if (flag_compile_solution_check_model) { Printer p(compiledSolutionCheckModel,0); p.print(m); } GCLock lock; vector typeErrors; MiniZinc::typecheck(*env, m, typeErrors, flag_model_types_only || flag_model_interface_only || flag_model_check_only, flag_allow_multi_assign); if (typeErrors.size() > 0) { for (unsigned int i=0; i typeErrors; MiniZinc::typecheck(*env, m, typeErrors, flag_model_check_only || flag_model_interface_only, flag_allow_multi_assign, true); if (typeErrors.size() > 0) { for (unsigned int i=0; iswap(); populateOutput(*env); } else { if (flag_verbose) log << "Flattening ..."; fopts.onlyRangeDomains = flag_only_range_domains; fopts.verbose = flag_verbose; fopts.outputMode = flag_output_mode; fopts.outputObjective = flag_output_objective; fopts.outputOutputItem = flag_output_output_item; #ifdef HAS_GECODE GecodeOptions gopts; gopts.only_range_domains = flag_only_range_domains; gopts.sac = flag_sac; gopts.allow_unbounded_vars = flag_allow_unbounded_vars; gopts.shave = flag_shave; gopts.printStatistics = flag_statistics; gopts.pre_passes = flag_pre_passes; #endif FlatteningOptions pass_opts = fopts; CompilePassFlags cfs; cfs.noMIPdomains = flag_noMIPdomains; cfs.verbose = flag_verbose; cfs.statistics = flag_statistics; cfs.optimize = flag_optimize; cfs.chain_compression = flag_chain_compression; cfs.newfzn = flag_newfzn; cfs.werror = flag_werror; cfs.model_check_only = flag_model_check_only; cfs.model_interface_only = flag_model_interface_only; cfs.allow_multi_assign = flag_allow_multi_assign; std::vector > managed_passes; if(flag_two_pass) { std::string library = std_lib_dir + (flag_gecode ? "/gecode_presolver/" : "/std/"); bool differentLibrary = (library!=std_lib_dir+"/"+globals_dir+"/"); managed_passes.emplace_back(new CompilePass(env, pass_opts, cfs, library, includePaths, true, differentLibrary)); #ifdef HAS_GECODE if(flag_gecode) managed_passes.emplace_back(new GecodePass(&gopts)); #endif } managed_passes.emplace_back(new CompilePass(env, fopts, cfs, std_lib_dir+"/"+globals_dir+"/", includePaths, flag_two_pass, false)); Env* out_env = multiPassFlatten(managed_passes); if(out_env == nullptr) exit(EXIT_FAILURE); if(out_env != env) { pEnv.reset(out_env); } env = out_env; if (flag_verbose) log << " done (" << starttime.stoptime() << ")," << " max stack depth " << env->maxCallStack() << std::endl; } if (flag_statistics) { FlatModelStatistics stats = statistics(*env); os << "% Generated FlatZinc statistics:\n"; os << "%%%mzn-stat: paths=" << env->envi().getPathMap().size() << endl; if (stats.n_bool_vars) { os << "%%%mzn-stat: flatBoolVars=" << stats.n_bool_vars << endl; } if (stats.n_int_vars) { os << "%%%mzn-stat: flatIntVars=" << stats.n_int_vars << endl; } if (stats.n_float_vars) { os << "%%%mzn-stat: flatFloatVars=" << stats.n_float_vars << endl; } if (stats.n_set_vars) { os << "%%%mzn-stat: flatSetVars=" << stats.n_set_vars << endl; } if (stats.n_bool_ct) { os << "%%%mzn-stat: flatBoolConstraints=" << stats.n_bool_ct << endl; } if (stats.n_int_ct) { os << "%%%mzn-stat: flatIntConstraints=" << stats.n_int_ct << endl; } if (stats.n_float_ct) { os << "%%%mzn-stat: flatFloatConstraints=" << stats.n_float_ct << endl; } if (stats.n_set_ct) { os << "%%%mzn-stat: flatSetConstraints=" << stats.n_set_ct << endl; } if (stats.n_reif_ct) { os << "%%%mzn-stat: evaluatedReifiedConstraints=" << stats.n_reif_ct << endl; } if (stats.n_imp_ct) { os << "%%%mzn-stat: evaluatedHalfReifiedConstraints=" << stats.n_imp_ct << endl; } if (stats.n_imp_del) { os << "%%%mzn-stat: eliminatedImplications=" << stats.n_imp_del << endl; } if (stats.n_lin_del) { os << "%%%mzn-stat: eliminatedLinearConstraints=" << stats.n_lin_del << endl; } /// Objective / SAT. These messages are used by mzn-test.py. SolveI* solveItem = env->flat()->solveItem(); if (solveItem->st() != SolveI::SolveType::ST_SAT) { if (solveItem->st() == SolveI::SolveType::ST_MAX) { os << "%%%mzn-stat: method=\"maximize\"" << endl; } else { os << "%%%mzn-stat: method=\"minimize\"" << endl; } } else { os << "%%%mzn-stat: method=\"satisfy\"" << endl; } os << "%%%mzn-stat: flatTime=" << flatten_time.s() << endl; os << "%%%mzn-stat-end" << endl << endl; } if (flag_output_paths_stdout) { if (flag_verbose) log << "Printing Paths to stdout ..." << std::endl; PathFilePrinter pfp(os, env->envi()); pfp.print(env->flat()); if (flag_verbose) log << " done (" << starttime.stoptime() << ")" << std::endl; } else if (flag_output_paths != "") { if (flag_verbose) log << "Printing Paths to '" << flag_output_paths << "' ..." << std::flush; std::ofstream ofs; ofs.open(flag_output_paths.c_str(), ios::out); checkIOStatus (ofs.good(), " I/O error: cannot open fzn output file. "); PathFilePrinter pfp(ofs, env->envi()); pfp.print(env->flat()); checkIOStatus (ofs.good(), " I/O error: cannot write fzn output file. "); ofs.close(); if (flag_verbose) log << " done (" << starttime.stoptime() << ")" << std::endl; } if ( (fopts.collect_mzn_paths || flag_two_pass) && !flag_keep_mzn_paths) { class RemovePathAnnotations : public ItemVisitor { public: void removePath(Annotation& a) const { a.removeCall(constants().ann.mzn_path); } void vVarDeclI(VarDeclI* vdi) const { removePath(vdi->e()->ann()); } void vConstraintI(ConstraintI* ci) const { removePath(ci->e()->ann()); } void vSolveI(SolveI* si) const { removePath(si->ann()); if(Expression* e = si->e()) removePath(e->ann()); } } removePaths; iterItems(removePaths, env->flat()); } if (flag_output_fzn_stdout) { if (flag_verbose) log << "Printing FlatZinc to stdout ..." << std::endl; Printer p(os,0); p.print(env->flat()); if (flag_verbose) log << " done (" << starttime.stoptime() << ")" << std::endl; } else if(flag_output_fzn != "") { if (flag_verbose) log << "Printing FlatZinc to '" << flag_output_fzn << "' ..." << std::flush; std::ofstream ofs; ofs.open(flag_output_fzn.c_str(), ios::out); checkIOStatus (ofs.good(), " I/O error: cannot open fzn output file. "); Printer p(ofs,0); p.print(env->flat()); checkIOStatus (ofs.good(), " I/O error: cannot write fzn output file. "); ofs.close(); if (flag_verbose) log << " done (" << starttime.stoptime() << ")" << std::endl; } if (!flag_no_output_ozn) { if (flag_output_ozn_stdout) { if (flag_verbose) log << "Printing .ozn to stdout ..." << std::endl; Printer p(os,0); p.print(env->output()); if (flag_verbose) log << " done (" << starttime.stoptime() << ")" << std::endl; } else if (flag_output_ozn != "") { if (flag_verbose) log << "Printing .ozn to '" << flag_output_ozn << "' ..." << std::flush; std::ofstream ofs; ofs.open(flag_output_ozn.c_str(), std::ios::out); checkIOStatus (ofs.good(), " I/O error: cannot open ozn output file. "); Printer p(ofs,0); p.print(env->output()); checkIOStatus (ofs.good(), " I/O error: cannot write ozn output file. "); ofs.close(); if (flag_verbose) log << " done (" << starttime.stoptime() << ")" << std::endl; } } } } else { // !flag_typecheck Printer p(os); p.print(m); } } if (getEnv()->envi().failed()) { status = SolverInstance::UNSAT; } if (flag_verbose) { size_t mem = GC::maxMem(); if (mem < 1024) log << "Maximum memory " << mem << " bytes"; else if (mem < 1024*1024) log << "Maximum memory " << mem/1024 << " Kbytes"; else log << "Maximum memory " << mem/(1024*1024) << " Mbytes"; log << "." << std::endl; } } void Flattener::printStatistics(ostream&) { } libminizinc-2.4.2/lib/gc.cpp000066400000000000000000000602021360574160400156770ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include #include #include //#define MINIZINC_GC_STATS #if defined(MINIZINC_GC_STATS) #include #endif namespace MiniZinc { GC*& GC::gc(void) { #if defined(HAS_DECLSPEC_THREAD) __declspec (thread) static GC* gc = NULL; #elif defined(HAS_ATTR_THREAD) static __thread GC* gc = NULL; #else #error Need thread-local storage #endif return gc; } bool GC::locked(void) { assert(gc()); return gc()->_lock_count > 0; } GCLock::GCLock(void) { GC::lock(); } GCLock::~GCLock(void) { GC::unlock(); } class FreeListNode : public ASTNode { public: FreeListNode* next; size_t size; FreeListNode(size_t s, FreeListNode* n) : ASTNode(ASTNode::NID_FL) , next(n) , size(s) { _gc_mark = 1; } FreeListNode(size_t s) : ASTNode(ASTNode::NID_FL), next(NULL), size(s) {} }; class HeapPage { public: HeapPage* next; size_t size; size_t used; char data[1]; HeapPage(HeapPage* n, size_t s) : next(n), size(s), used(0) {} }; /// Memory managed by the garbage collector class GC::Heap { friend class GC; #if defined(MINIZINC_GC_STATS) static const char* _nodeid[Item::II_END+1]; struct GCStat { int first; int second; int keepalive; int inmodel; size_t total; GCStat(void) : first(0), second(0), keepalive(0), inmodel(0), total(0) {} }; std::map gc_stats; #endif protected: static const size_t _min_gc_threshold; HeapPage* _page; Model* _rootset; KeepAlive* _roots; WeakRef* _weakRefs; ASTNodeWeakMap* _nodeWeakMaps; static const int _max_fl = 5; FreeListNode* _fl[_max_fl+1]; static const size_t _fl_size[_max_fl+1]; int _fl_slot(size_t _size) { size_t size = _size; assert(size <= _fl_size[_max_fl]); assert(size >= _fl_size[0]); size -= sizeof(Item); assert(size % sizeof(void*) == 0); size /= sizeof(void*); assert(size >= 1); int slot = static_cast(size)-1; return slot; } /// Total amount of memory allocated size_t _alloced_mem; /// Total amount of memory currently free size_t _free_mem; /// Memory threshold for next garbage collection size_t _gc_threshold; /// High water mark of all allocated memory size_t _max_alloced_mem; /// A trail item struct TItem { Expression** l; Expression* v; bool mark; TItem(Expression** l0, Expression* v0) : l(l0), v(v0), mark(false) {} }; /// Trail std::vector trail; Heap(void) : _page(NULL) , _rootset(NULL) , _roots(NULL) , _weakRefs(NULL) , _nodeWeakMaps(NULL) , _alloced_mem(0) , _free_mem(0) , _gc_threshold(_min_gc_threshold) , _max_alloced_mem(0) { for (int i=_max_fl+1; i--;) _fl[i] = NULL; } /// Default size of pages to allocate static const size_t pageSize = 1<<20; HeapPage* allocPage(size_t s, bool exact=false) { if (!exact) s = std::max(s,pageSize); HeapPage* newPage = static_cast(::malloc(sizeof(HeapPage)+s-1)); if (newPage==NULL) { throw InternalError("out of memory"); } #ifndef NDEBUG memset(newPage,255,sizeof(HeapPage)+s-1); #endif _alloced_mem += s; _max_alloced_mem = std::max(_max_alloced_mem, _alloced_mem); _free_mem += s; if (exact && _page) { new (newPage) HeapPage(_page->next,s); _page->next = newPage; } else { if (_page) { size_t ns = _page->size-_page->used; assert(ns <= _fl_size[_max_fl]); if (ns >= _fl_size[0]) { // Remainder of page can be added to free lists FreeListNode* fln = reinterpret_cast(_page->data+_page->used); _page->used += ns; new (fln) FreeListNode(ns, _fl[_fl_slot(ns)]); _fl[_fl_slot(ns)] = fln; } else { // Waste a little memory (less than smallest free list slot) _free_mem -= ns; assert(_alloced_mem >= _free_mem); } } new (newPage) HeapPage(_page,s); _page = newPage; } return newPage; } void* alloc(size_t size, bool exact=false) { assert(size<=80 || exact); /// Align to word boundary size += ((8 - (size & 7)) & 7); HeapPage* p = _page; if (exact || _page==NULL || _page->used+size >= _page->size) p = allocPage(size,exact); char* ret = p->data+p->used; p->used += size; _free_mem -= size; if (p->size-p->used < _fl_size[0]) { _free_mem -= (p->size-p->used); _alloced_mem -= (p->size-p->used); p->size=p->used; } assert(_alloced_mem >= _free_mem); return ret; } /// Allocate one object of type T (no initialisation) template T* alloc(void) { return static_cast(alloc(sizeof(T))); } /// Allocate \a n objects of type T (no initialisation) template T* alloc(int n) { return static_cast(alloc(n*sizeof(T))); } void* fl(size_t size) { int slot = _fl_slot(size); assert(slot <= _max_fl); if (_fl[slot]) { FreeListNode* p = _fl[slot]; _fl[slot] = p->next; _free_mem -= size; return p; } return alloc(size); } void trigger(void) { #ifdef MINIZINC_GC_STATS std::cerr << "GC\n\talloced " << (_alloced_mem/1024) << "\n\tfree " << (_free_mem/1024) << "\n\tdiff " << ((_alloced_mem-_free_mem)/1024) << "\n\tthreshold " << (_gc_threshold/1024) << "\n"; #endif size_t old_free = _free_mem; mark(); sweep(); // GC strategy: // increase threshold if either // a) we haven't been able to put much on the free list (comapred to before GC), or // b) the free list memory (after GC) is less than 50% of the allocated memory // otherwise (i.e., we have been able to increase the free list, and it is now more // than 50% of overall allocated memory), keep threshold at allocated memory if ( (old_free!= 0 && static_cast(old_free)/static_cast(_free_mem) > 0.9) || static_cast(_free_mem)/_alloced_mem < 0.5) { _gc_threshold = std::max(_min_gc_threshold,static_cast(_alloced_mem * 1.5)); } else { _gc_threshold = std::max(_min_gc_threshold,_alloced_mem); } #ifdef MINIZINC_GC_STATS std::cerr << "done\n\talloced " << (_alloced_mem/1024) << "\n\tfree " << (_free_mem/1024) << "\n\tdiff " << ((_alloced_mem-_free_mem)/1024) << "\n\tthreshold " << (_gc_threshold/1024) << "\n"; #endif } void rungc(void) { if (_alloced_mem > _gc_threshold) { trigger(); } } void mark(void); void sweep(void); static size_t nodesize(ASTNode* n) { static const size_t _nodesize[Item::II_END+1] = { 0, // NID_FL 0, // NID_CHUNK 0, // NID_VEC sizeof(IntLit), // E_INTLIT sizeof(FloatLit), // E_FLOATLIT sizeof(SetLit), // E_SETLIT sizeof(BoolLit), // E_BOOLLIT sizeof(StringLit), // E_STRINGLIT sizeof(Id), // E_ID sizeof(AnonVar), // E_ANON sizeof(ArrayLit), // E_ARRAYLIT sizeof(ArrayAccess), // E_ARRAYACCESS sizeof(Comprehension), // E_COMP sizeof(ITE), // E_ITE sizeof(BinOp), // E_BINOP sizeof(UnOp), // E_UNOP sizeof(Call), // E_CALL sizeof(VarDecl), // E_VARDECL sizeof(Let), // E_LET sizeof(TypeInst), // E_TI sizeof(TIId), // E_TIID sizeof(IncludeI), // II_INC sizeof(VarDeclI), // II_VD sizeof(AssignI), // II_ASN sizeof(ConstraintI), // II_CON sizeof(SolveI), // II_SOL sizeof(OutputI), // II_OUT sizeof(FunctionI) // II_FUN }; size_t ns; switch (n->_id) { case ASTNode::NID_FL: ns = static_cast(n)->size; break; case ASTNode::NID_CHUNK: ns = static_cast(n)->memsize(); break; case ASTNode::NID_VEC: ns = static_cast(n)->memsize(); break; case Call::eid: ns = n->_flag_1 ? _nodesize[BinOp::eid] : _nodesize[Call::eid]; break; default: assert(n->_id <= Item::II_END); ns = _nodesize[n->_id]; break; } ns += ((8 - (ns & 7)) & 7); return ns; } }; const size_t GC::Heap::_min_gc_threshold = 10ll*1024ll; #ifdef MINIZINC_GC_STATS const char* GC::Heap::_nodeid[] = { "FreeList ", // NID_FL "Chunk ", // NID_CHUNK "Vec ", // NID_VEC "IntLit ", // E_INTLIT "FloatLit ", // E_FLOATLIT "SetLit ", // E_SETLIT "BoolLit ", // E_BOOLLIT "StringLit ", // E_STRINGLIT "Id ", // E_ID "AnonVar ", // E_ANON "ArrayLit ", // E_ARRAYLIT "ArrayAccess ", // E_ARRAYACCESS "Comprehension ", // E_COMP "ITE ", // E_ITE "BinOp ", // E_BINOP "UnOp ", // E_UNOP "Call ", // E_CALL "VarDecl ", // E_VARDECL "Let ", // E_LET "TypeInst ", // E_TI "TIId ", // E_TIID "IncludeI ", // II_INC "VarDeclI ", // II_VD "AssignI ", // II_ASN "ConstraintI ", // II_CON "SolveI ", // II_SOL "OutputI ", // II_OUT "FunctionI " // II_FUN }; #endif void GC::setTimeout(unsigned long long int t) { if (gc()==NULL) { gc() = new GC(); } gc()->_timeout = t; gc()->_timeout_timer.reset(); } void GC::lock(void) { if (gc()==NULL) { gc() = new GC(); } // If a timeout has been specified, first check counter // before checking timer (counter is much cheaper, introduces // less overhead) if (gc()->_timeout > 0 && gc()->_timeout_counter++ > 500) { gc()->_timeout_counter = 0; if (gc()->_timeout_timer.ms() > gc()->_timeout) { gc()->_timeout = 0; gc()->_timeout_counter = 0; throw Timeout(); } } if (gc()->_lock_count==0) { gc()->_heap->rungc(); } gc()->_lock_count++; } void GC::unlock(void) { assert(locked()); gc()->_lock_count--; } void GC::trigger(void) { if (!locked()) gc()->_heap->trigger(); } const size_t GC::Heap::pageSize; const size_t GC::Heap::_fl_size[GC::Heap::_max_fl+1] = { sizeof(Item)+1*sizeof(void*), sizeof(Item)+2*sizeof(void*), sizeof(Item)+3*sizeof(void*), sizeof(Item)+4*sizeof(void*), sizeof(Item)+5*sizeof(void*), sizeof(Item)+6*sizeof(void*), }; GC::GC(void) : _heap(new Heap()), _lock_count(0), _timeout(0), _timeout_counter(0) {} void GC::add(Model* m) { GC* gc = GC::gc(); if (gc->_heap->_rootset) { m->_roots_next = gc->_heap->_rootset; m->_roots_prev = m->_roots_next->_roots_prev; m->_roots_prev->_roots_next = m; m->_roots_next->_roots_prev = m; } else { gc->_heap->_rootset = m->_roots_next = m->_roots_prev = m; } } void GC::remove(Model* m) { GC* gc = GC::gc(); if (m->_roots_next == m) { gc->_heap->_rootset = NULL; } else { m->_roots_next->_roots_prev = m->_roots_prev; m->_roots_prev->_roots_next = m->_roots_next; if (m==gc->_heap->_rootset) gc->_heap->_rootset = m->_roots_prev; } } void* GC::alloc(size_t size) { assert(locked()); void* ret; if (size < _heap->_fl_size[0] || size > _heap->_fl_size[_heap->_max_fl]) { ret = _heap->alloc(size,true); } else { ret = _heap->fl(size); } new (ret) FreeListNode(size); return ret; } void GC::Heap::mark(void) { #if defined(MINIZINC_GC_STATS) std::cerr << "================= mark =================: "; gc_stats.clear(); #endif for (KeepAlive* e = _roots; e != NULL; e = e->next()) { if ((*e)() && (*e)()->_gc_mark==0) { Expression::mark((*e)()); #if defined(MINIZINC_GC_STATS) gc_stats[(*e)()->_id].keepalive++; #endif } } #if defined(MINIZINC_GC_STATS) std::cerr << "+"; #endif Model* m = _rootset; if (m==NULL) return; do { m->_filepath.mark(); m->_filename.mark(); for (unsigned int j=0; j_items.size(); j++) { Item* i = m->_items[j]; if (i->_gc_mark==0) { i->_gc_mark = 1; i->loc().mark(); switch (i->iid()) { case Item::II_INC: i->cast()->f().mark(); break; case Item::II_VD: Expression::mark(i->cast()->e()); #if defined(MINIZINC_GC_STATS) gc_stats[i->cast()->e()->Expression::eid()].inmodel++; #endif break; case Item::II_ASN: i->cast()->id().mark(); Expression::mark(i->cast()->e()); Expression::mark(i->cast()->decl()); break; case Item::II_CON: Expression::mark(i->cast()->e()); #if defined(MINIZINC_GC_STATS) gc_stats[i->cast()->e()->Expression::eid()].inmodel++; #endif break; case Item::II_SOL: { SolveI* si = i->cast(); for (ExpressionSetIter it = si->ann().begin(); it != si->ann().end(); ++it) { Expression::mark(*it); } } Expression::mark(i->cast()->e()); break; case Item::II_OUT: Expression::mark(i->cast()->e()); break; case Item::II_FUN: { FunctionI* fi = i->cast(); fi->id().mark(); Expression::mark(fi->ti()); for (ExpressionSetIter it = fi->ann().begin(); it != fi->ann().end(); ++it) { Expression::mark(*it); } Expression::mark(fi->e()); fi->params().mark(); for (unsigned int k=0; kparams().size(); k++) { Expression::mark(fi->params()[k]); } } break; } } } m = m->_roots_next; } while (m != _rootset); for (unsigned int i=static_cast(trail.size()); i--;) { Expression::mark(trail[i].v); } bool fixPrev = false; WeakRef* prevWr = NULL; for (WeakRef* wr = _weakRefs; wr != NULL; wr = wr->next()) { if (fixPrev) { fixPrev = false; removeWeakRef(prevWr); prevWr->_n = NULL; prevWr->_p = NULL; } if ((*wr)() && (*wr)()->_gc_mark==0) { wr->_e = NULL; wr->_valid = false; fixPrev = true; prevWr = wr; } } if (fixPrev) { removeWeakRef(prevWr); prevWr->_n = NULL; prevWr->_p = NULL; } for (ASTNodeWeakMap* wr = _nodeWeakMaps; wr != NULL; wr = wr->next()) { std::vector toRemove; for (auto n : wr->_m) { if (n.first->_gc_mark==0 || n.second->_gc_mark==0) toRemove.push_back(n.first); } for (auto n : toRemove) { wr->_m.erase(n); } } #if defined(MINIZINC_GC_STATS) std::cerr << "+"; std::cerr << "\n"; #endif } void GC::Heap::sweep(void) { #if defined(MINIZINC_GC_STATS) std::cerr << "=============== GC sweep =============\n"; #endif HeapPage* p = _page; HeapPage* prev = NULL; while (p) { size_t off = 0; bool wholepage = true; struct NodeInfo { ASTNode* n; size_t ns; NodeInfo(ASTNode* n0, size_t ns0) : n(n0), ns(ns0) {} }; std::vector freeNodes; freeNodes.reserve(100); while (off < p->used) { ASTNode* n = reinterpret_cast(p->data+off); size_t ns = nodesize(n); assert(ns != 0); #if defined(MINIZINC_GC_STATS) GCStat& stats = gc_stats[n->_id]; stats.first++; stats.total += ns; #endif if (n->_gc_mark==0) { switch (n->_id) { case Item::II_FUN: static_cast(n)->ann().~Annotation(); break; case Item::II_SOL: static_cast(n)->ann().~Annotation(); break; case Expression::E_VARDECL: // Reset WeakRef inside VarDecl static_cast(n)->flat(NULL); // fall through default: if (n->_id >= ASTNode::NID_END+1 && n->_id <= Expression::EID_END) { static_cast(n)->ann().~Annotation(); } } if (ns >= _fl_size[0] && ns <= _fl_size[_max_fl]) { freeNodes.push_back(NodeInfo(n,ns)); } else { assert(off==0); assert(p->used==p->size); } } else { #if defined(MINIZINC_GC_STATS) stats.second++; #endif wholepage = false; if (n->_id != ASTNode::NID_FL) n->_gc_mark=0; } off += ns; } if (wholepage) { #ifndef NDEBUG memset(p->data,42,p->size); #endif if (prev) { prev->next = p->next; } else { assert(p==_page); _page = p->next; } HeapPage* pf = p; p = p->next; _alloced_mem -= pf->size; if (pf->size-pf->used >= _fl_size[0]) _free_mem -= (pf->size-pf->used); assert(_alloced_mem >= _free_mem); ::free(pf); } else { for (auto ni : freeNodes) { FreeListNode* fln = static_cast(ni.n); new (fln) FreeListNode(ni.ns, _fl[_fl_slot(ni.ns)]); _fl[_fl_slot(ni.ns)] = fln; _free_mem += ni.ns; #if defined(MINIZINC_GC_STATS) gc_stats[fln->_id].second++; #endif } assert(_alloced_mem >= _free_mem); prev = p; p = p->next; } } #if defined(MINIZINC_GC_STATS) for (auto stat: gc_stats) { std::cerr << _nodeid[stat.first] << ":\t" << stat.second.first << " / " << stat.second.second << " / " << stat.second.keepalive << " / " << stat.second.inmodel << " / "; if (stat.second.total > 1024) { if (stat.second.total > 1024*1024) { std::cerr << (stat.second.total / 1024 / 1024) << "M"; } else { std::cerr << (stat.second.total / 1024) << "K"; } } else { std::cerr << (stat.second.total); } std::cerr << std::endl; } #endif } ASTVec::ASTVec(size_t size) : ASTNode(NID_VEC), _size(size) {} void* ASTVec::alloc(size_t size) { size_t s = sizeof(ASTVec)+(size<=2?0:size-2)*sizeof(void*); s += ((8 - (s & 7)) & 7); return GC::gc()->alloc(s); } ASTChunk::ASTChunk(size_t size) : ASTNode(NID_CHUNK), _size(size) {} void* ASTChunk::alloc(size_t size) { size_t s = sizeof(ASTChunk)+(size<=4?0:size-4)*sizeof(char); s += ((8 - (s & 7)) & 7); return GC::gc()->alloc(s); } void GC::mark(void) { GC* gc = GC::gc(); if (!gc->_heap->trail.empty()) gc->_heap->trail.back().mark = true; } void GC::trail(Expression** l,Expression* v) { GC* gc = GC::gc(); gc->_heap->trail.push_back(GC::Heap::TItem(l,v)); } void GC::untrail(void) { GC* gc = GC::gc(); while (!gc->_heap->trail.empty() && !gc->_heap->trail.back().mark) { *gc->_heap->trail.back().l = gc->_heap->trail.back().v; gc->_heap->trail.pop_back(); } if (!gc->_heap->trail.empty()) gc->_heap->trail.back().mark = false; } size_t GC::maxMem(void) { GC* gc = GC::gc(); return gc->_heap->_max_alloced_mem; } void* ASTNode::operator new(size_t size) { return GC::gc()->alloc(size); } void GC::addKeepAlive(KeepAlive* e) { assert(e->_p==NULL); assert(e->_n==NULL); e->_n = GC::gc()->_heap->_roots; if (GC::gc()->_heap->_roots) GC::gc()->_heap->_roots->_p = e; GC::gc()->_heap->_roots = e; } void GC::removeKeepAlive(KeepAlive* e) { if (e->_p) { e->_p->_n = e->_n; } else { assert(GC::gc()->_heap->_roots==e); GC::gc()->_heap->_roots = e->_n; } if (e->_n) { e->_n->_p = e->_p; } } KeepAlive::KeepAlive(Expression* e) : _e(e), _p(NULL), _n(NULL) { if (_e && !_e->isUnboxedVal()) GC::gc()->addKeepAlive(this); } KeepAlive::~KeepAlive(void) { if (_e && !_e->isUnboxedVal()) GC::gc()->removeKeepAlive(this); } KeepAlive::KeepAlive(const KeepAlive& e) : _e(e._e), _p(NULL), _n(NULL) { if (_e && !_e->isUnboxedVal()) GC::gc()->addKeepAlive(this); } KeepAlive& KeepAlive::operator =(const KeepAlive& e) { if (_e && !_e->isUnboxedVal()) { if (e._e==NULL || e._e->isUnboxedVal()) { GC::gc()->removeKeepAlive(this); _p = _n = NULL; } } else { if (e._e!=NULL && !e._e->isUnboxedVal()) GC::gc()->addKeepAlive(this); } _e = e._e; return *this; } void GC::addWeakRef(WeakRef* e) { assert(e->_p==NULL); assert(e->_n==NULL); e->_n = GC::gc()->_heap->_weakRefs; if (GC::gc()->_heap->_weakRefs) GC::gc()->_heap->_weakRefs->_p = e; GC::gc()->_heap->_weakRefs = e; } void GC::removeWeakRef(MiniZinc::WeakRef *e) { if (e->_p) { e->_p->_n = e->_n; } else { assert(GC::gc()->_heap->_weakRefs==e); GC::gc()->_heap->_weakRefs = e->_n; } if (e->_n) { e->_n->_p = e->_p; } } void GC::addNodeWeakMap(ASTNodeWeakMap* m) { assert(m->_p==NULL); assert(m->_n==NULL); m->_n = GC::gc()->_heap->_nodeWeakMaps; if (GC::gc()->_heap->_nodeWeakMaps) GC::gc()->_heap->_nodeWeakMaps->_p = m; GC::gc()->_heap->_nodeWeakMaps = m; } void GC::removeNodeWeakMap(ASTNodeWeakMap* m) { if (m->_p) { m->_p->_n = m->_n; } else { assert(GC::gc()->_heap->_nodeWeakMaps==m); GC::gc()->_heap->_nodeWeakMaps = m->_n; } if (m->_n) { m->_n->_p = m->_p; } } WeakRef::WeakRef(Expression* e) : _e(e), _p(NULL), _n(NULL), _valid(true) { if (_e && !_e->isUnboxedVal()) GC::gc()->addWeakRef(this); } WeakRef::~WeakRef(void) { if (_e && !_e->isUnboxedVal()) GC::gc()->removeWeakRef(this); } WeakRef::WeakRef(const WeakRef& e) : _e(e()), _p(NULL), _n(NULL), _valid(true) { if (_e && !_e->isUnboxedVal()) GC::gc()->addWeakRef(this); } WeakRef& WeakRef::operator =(const WeakRef& e) { // Test if this WeakRef is currently active in the GC bool isActive = (_e && !_e->isUnboxedVal()); if (isActive) { // Yes, active WeakRef. // If after assigning WeakRef should be inactive, remove it. if (e()==NULL || e()->isUnboxedVal()) { GC::gc()->removeWeakRef(this); _n = _p = NULL; } } _e = e(); _valid = true; // If this WeakRef was not active but now should be, add it if (!isActive && _e!=NULL && !_e->isUnboxedVal()) GC::gc()->addWeakRef(this); return *this; } ASTNodeWeakMap::ASTNodeWeakMap(void) : _p(NULL), _n(NULL) { GC::gc()->addNodeWeakMap(this); } ASTNodeWeakMap::~ASTNodeWeakMap(void) { GC::gc()->removeNodeWeakMap(this); } void ASTNodeWeakMap::insert(ASTNode* n0, ASTNode* n1) { _m.insert(std::make_pair(n0,n1)); } ASTNode* ASTNodeWeakMap::find(ASTNode* n) { NodeMap::iterator it = _m.find(n); if (it==_m.end()) return NULL; return it->second; } } libminizinc-2.4.2/lib/htmlprinter.cpp000066400000000000000000001335211360574160400176630ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include #include #include namespace MiniZinc { namespace HtmlDocOutput { // Trim leading space: // - always trim first line completely // - second line defines the base indentation std::string trim(const std::string& s0) { std::string s = s0; // remove carriage returns size_t j=0; for (size_t i=0; i pos) { oss << s.substr(first_nl+1,std::string::npos); return oss.str(); } size_t lastpos = unindent; while (pos != std::string::npos) { oss << s.substr(lastpos, pos-lastpos) << "\n"; size_t next_indent = s.find_first_not_of(" \t", pos+1); if (next_indent==std::string::npos) { lastpos = next_indent; } else if (next_indent-(pos+1) < unindent) { lastpos = next_indent; } else { lastpos = pos+1+unindent; } pos = (lastpos == std::string::npos ? lastpos : s.find("\n", lastpos)); } if (lastpos != std::string::npos) oss << s.substr(lastpos, std::string::npos); return oss.str(); } class DocItem { public: enum DocType { T_PAR=0, T_VAR=1, T_FUN=2 }; DocItem(const DocType& t0, std::string id0, std::string sig0, std::string doc0) : t(t0), id(id0), sig(sig0), doc(doc0) {} DocType t; std::string id; std::string sig; std::string doc; }; typedef std::unordered_map FunMap; class Group; class GroupMap { public: typedef std::vector Map; Map m; ~GroupMap(); Map::iterator find(const std::string& n); }; class Group { public: Group(const std::string& name0, const std::string& fullPath0) : name(name0), fullPath(fullPath0) {} std::string name; std::string fullPath; std::string desc; std::string htmlName; GroupMap subgroups; std::vector items; std::string getAnchor(int level, int indivFileLevel) { if (level < indivFileLevel) { return fullPath + ".html"; } else { return "#" + fullPath; } } std::string toHTML(int level, int indivFileLevel, Group* parent, int idx, const std::string& basename, bool generateIndex) { std::ostringstream oss; int realLevel = (level < indivFileLevel) ? 0 : level - indivFileLevel; oss << "
\n"; if (parent) { oss << "
"; if (idx > 0) { oss << " "; } oss << " "; if (idx < parent->subgroups.m.size()-1) { oss << " "; } if (generateIndex) oss << "Index\n"; if (items.size() > 0) { oss << "reveal all\n"; oss << "hide all\n"; } oss << "
"; } if (!htmlName.empty()) { oss << "\n"; oss << "
\n" << desc << "
\n"; } if (subgroups.m.size() != 0) { oss << "

Sections:

\n"; oss << "
    \n"; for (GroupMap::Map::iterator it = subgroups.m.begin(); it != subgroups.m.end(); ++it) { oss << "
  • " << (*it)->htmlName << "\n"; if ((*it)->htmlName.empty()) { std::cerr << "Warning: undocumented group " << (*it)->fullPath << "\n"; } } oss << "
\n"; if (parent==NULL && generateIndex) { oss << "

Index

\n"; } if (items.size() > 0) oss << "

Declarations in this section:

\n"; } struct SortById { bool operator ()(const DocItem& i0, const DocItem& i1) { return i0.t < i1.t || (i0.t==i1.t && i0.id < i1.id); } } _cmp; std::stable_sort(items.begin(), items.end(), _cmp); int cur_t = -1; const char* dt[] = {"par","var","fun"}; const char* dt_desc[] = {"Parameters","Variables","Functions and Predicates"}; for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) { if (it->t != cur_t) { if (cur_t != -1) oss << "
\n"; cur_t = it->t; oss << "
\n"; oss << "
" << dt_desc[cur_t] << "
\n"; } oss << it->doc; } if (cur_t != -1) oss << "
\n"; if (level >= indivFileLevel) { for (unsigned int i=0; itoHTML(level+1, indivFileLevel, this, i, basename, generateIndex); } } oss << ""; return oss.str(); } static std::string rstHeading(std::string s, int level) { std::vector levelChar({'#','=','-','^','+','"'}); std::ostringstream oss; oss << s << "\n"; for (int i=0; itoRST(level+1); } if (items.size() > 0) { if (subgroups.m.size()!=0) { oss << rstHeading("Other declarations", level+1); } struct SortById { bool operator ()(const DocItem& i0, const DocItem& i1) { return i0.t < i1.t || (i0.t==i1.t && i0.id < i1.id); } } _cmp; std::stable_sort(items.begin(), items.end(), _cmp); int cur_t = -1; int nHeadings = 0; for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) { if (it->t != cur_t) { cur_t = it->t; nHeadings++; } } cur_t = -1; const char* dt_desc[] = {"Parameters","Variables","Functions and Predicates"}; for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) { if (it->t != cur_t) { cur_t = it->t; if (nHeadings > 1) oss << rstHeading(dt_desc[cur_t], subgroups.m.size()==0 ? level+1 : level+2); } oss << it->doc; } } return oss.str(); } }; GroupMap::~GroupMap() { for (Map::iterator it = m.begin(); it != m.end(); ++it) { delete *it; } } GroupMap::Map::iterator GroupMap::find(const std::string& n) { for (Map::iterator it = m.begin(); it != m.end(); ++it) if ((*it)->name == n) return it; return m.end(); } void addToGroup(Group& gm, const std::string& group, DocItem& di) { std::vector subgroups; size_t lastpos = 0; size_t pos = group.find("."); while (pos != std::string::npos) { subgroups.push_back(group.substr(lastpos, pos-lastpos)); lastpos = pos+1; pos = group.find(".", lastpos); } subgroups.push_back(group.substr(lastpos, std::string::npos)); GroupMap* cgm = &gm.subgroups; std::string gpath(gm.fullPath); for (unsigned int i=0; ifind(subgroups[i]) == cgm->m.end()) { cgm->m.push_back(new Group(subgroups[i], gpath)); } Group& g = **cgm->find(subgroups[i]); if (i==subgroups.size()-1) { g.items.push_back(di); } else { cgm = &g.subgroups; } } } void setGroupDesc(Group& maingroup, const std::string& group, std::string htmlName, std::string s) { if (group == "MAIN") { if (!maingroup.htmlName.empty()) { std::cerr << "Warning: two descriptions for group `" << group << "'\n"; } maingroup.htmlName = htmlName; maingroup.desc = s; return; } std::vector subgroups; size_t lastpos = 0; size_t pos = group.find("."); while (pos != std::string::npos) { subgroups.push_back(group.substr(lastpos, pos-lastpos)); lastpos = pos+1; pos = group.find(".", lastpos); } subgroups.push_back(group.substr(lastpos, std::string::npos)); GroupMap* cgm = &maingroup.subgroups; std::string gpath(maingroup.fullPath); for (unsigned int i=0; ifind(subgroups[i]) == cgm->m.end()) { cgm->m.push_back(new Group(subgroups[i], gpath)); } Group& g = **cgm->find(subgroups[i]); if (i==subgroups.size()-1) { if (!g.htmlName.empty()) { std::cerr << "Warning: two descriptions for group `" << group << "'\n"; } g.htmlName = htmlName; g.desc = s; } else { cgm = &g.subgroups; } } } std::string extractArgWord(std::string& s, size_t n) { size_t start = n; while (start < s.size() && s[start]!=' ' && s[start]!='\t') start++; while (start < s.size() && (s[start]==' ' || s[start]=='\t')) start++; size_t end = start+1; while (end < s.size() && (isalnum(s[end]) || s[end]=='_' || s[end]=='.')) end++; std::string ret = s.substr(start,end-start); s = s.substr(end,std::string::npos); return ret; } std::string makeHTMLId(const std::string& ident) { std::ostringstream oss; oss << "I"; bool prevWasSym = false; for (size_t i=0; i' : oss << "-gr"; break; case '<': oss << "-lt"; break; case '/': oss << "-dv"; break; case '\\': oss << "-bs"; break; case '~': oss << "-tl"; break; case '\'': oss << "-tk"; break; case ' ': break; case '\t': break; case '\n': break; case ':': oss << "-cl"; break; case '[': oss << "-bo"; break; case ']': oss << "-bc"; break; case '$': oss << "-dd"; break; case '(': oss << "-po"; break; case ')': oss << "-pc"; break; case ',': oss << "-cm"; break; default: oss << (prevWasSym ? "-" : "") << ident[i]; isSym = false; break; } prevWasSym = isSym; } return oss.str(); } } class CollectFunctionsVisitor : public ItemVisitor { protected: EnvI& env; HtmlDocOutput::FunMap& _funmap; bool _includeStdLib; public: CollectFunctionsVisitor(EnvI& env0, HtmlDocOutput::FunMap& funmap, bool includeStdLib) : env(env0), _funmap(funmap), _includeStdLib(includeStdLib) {} bool enterModel(Model* m) { return _includeStdLib || m->filename()!="stdlib.mzn"; } void vFunctionI(FunctionI* fi) { if (Call* docstring = Expression::dyn_cast(getAnnotation(fi->ann(), constants().ann.doc_comment))) { std::string ds = eval_string(env,docstring->arg(0)); std::string group("main"); size_t group_idx = ds.find("@group"); if (group_idx!=std::string::npos) { group = HtmlDocOutput::extractArgWord(ds, group_idx); } _funmap.insert(std::make_pair(fi, group)); } } }; class PrintHtmlVisitor : public ItemVisitor { protected: EnvI& env; HtmlDocOutput::Group& _maingroup; HtmlDocOutput::FunMap& _funmap; bool _includeStdLib; std::vector replaceArgs(std::string& s) { std::vector replacements; std::ostringstream oss; size_t lastpos = 0; size_t pos = std::min(s.find("\\a"), s.find("\\p")); size_t mathjax_open = s.find("\\("); size_t mathjax_close = s.rfind("\\)"); if (pos == std::string::npos) return replacements; while (pos != std::string::npos) { oss << s.substr(lastpos, pos-lastpos); size_t start = pos; while (start < s.size() && s[start]!=' ' && s[start]!='\t') start++; while (start < s.size() && (s[start]==' ' || s[start]=='\t')) start++; size_t end = start+1; while (end < s.size() && (isalnum(s[end]) || s[end]=='_')) end++; if (s[pos+1]=='a') { replacements.push_back(s.substr(start,end-start)); if (pos >= mathjax_open && pos <= mathjax_close) { oss << "{\\bf " << replacements.back() << "}"; } else { oss << "" << replacements.back() << ""; } } else { if (pos >= mathjax_open && pos <= mathjax_close) { oss << "{\\bf " << s.substr(start,end-start) << "}"; } else { oss << "" << s.substr(start,end-start) << ""; } } lastpos = end; pos = std::min(s.find("\\a", lastpos), s.find("\\p", lastpos)); } oss << s.substr(lastpos, std::string::npos); s = oss.str(); return replacements; } std::pair extractArgLine(std::string& s, size_t n) { size_t start = n; while (start < s.size() && s[start]!=' ' && s[start]!='\t') start++; while (start < s.size() && (s[start]==' ' || s[start]=='\t')) start++; size_t end = start+1; while (end < s.size() && s[end]!=':') end++; std::string arg = s.substr(start,end-start); size_t doc_start = end+1; while (end < s.size() && s[end]!='\n') end++; std::string ret = s.substr(doc_start,end-doc_start); replaceArgs(ret); s = s.substr(0,n)+s.substr(end,std::string::npos); return make_pair(arg,ret); } std::string addHTML(const std::string& s) { std::ostringstream oss; size_t lastpos = 0; size_t pos = s.find('\n'); bool inUl = false; oss << "

\n"; while (pos != std::string::npos) { oss << s.substr(lastpos, pos-lastpos); size_t next = std::min(s.find('\n', pos+1),s.find('-', pos+1)); if (next==std::string::npos) { lastpos = pos+1; break; } bool allwhite = true; for (size_t cur = pos+1; cur < next; cur++) { if (s[cur]!=' ' && s[cur]!='\t') { allwhite = false; break; } } if (allwhite) { if (s[next]=='-') { if (!inUl) { oss << "

    \n"; inUl = true; } oss << "
  • "; } else { if (inUl) { oss << "
\n"; inUl = false; } else { oss << "

\n"; } } lastpos = next+1; pos = s.find('\n', lastpos); } else { lastpos = pos+1; if (s[pos]=='\n') { oss << " "; } if (s[next]=='-') { pos = s.find('\n', next+1); } else { pos = next; } } } oss << s.substr(lastpos, std::string::npos); if (inUl) oss << "\n"; oss << "

\n"; return oss.str(); } public: PrintHtmlVisitor(EnvI& env0, HtmlDocOutput::Group& mg, HtmlDocOutput::FunMap& fm, bool includeStdLib) : env(env0), _maingroup(mg), _funmap(fm), _includeStdLib(includeStdLib) {} bool enterModel(Model* m) { if (!_includeStdLib && m->filename()=="stdlib.mzn") return false; const std::string& dc = m->docComment(); if (!dc.empty()) { size_t gpos = dc.find("@groupdef"); while (gpos != std::string::npos) { size_t start = gpos; while (start < dc.size() && dc[start]!=' ' && dc[start]!='\t') start++; while (start < dc.size() && (dc[start]==' ' || dc[start]=='\t')) start++; size_t end = start+1; while (end < dc.size() && (isalnum(dc[end]) || dc[end]=='_' || dc[end]=='.')) end++; std::string groupName = dc.substr(start,end-start); size_t doc_start = end+1; while (end < dc.size() && dc[end]!='\n') end++; std::string groupHTMLName = dc.substr(doc_start,end-doc_start); size_t next = dc.find("@groupdef", gpos+1); HtmlDocOutput::setGroupDesc(_maingroup, groupName, groupHTMLName, addHTML(dc.substr(end, next == std::string::npos ? next : next-end))); gpos = next; } } return true; } /// Visit variable declaration void vVarDeclI(VarDeclI* vdi) { if (Call* docstring = Expression::dyn_cast(getAnnotation(vdi->e()->ann(), constants().ann.doc_comment))) { std::string ds = eval_string(env,docstring->arg(0)); std::string group("main"); size_t group_idx = ds.find("@group"); if (group_idx!=std::string::npos) { group = HtmlDocOutput::extractArgWord(ds, group_idx); } std::ostringstream os; std::string sig = vdi->e()->type().toString(env)+" "+vdi->e()->id()->str().str(); os << "
\n"; os << "
\n"; if (vdi->e()->ti()->type() == Type::ann()) { os << "annotation "; os << "" << *vdi->e()->id() << ""; } else { os << *vdi->e()->ti() << ": " << *vdi->e()->id(); } os << "
\n"; os << addHTML(ds); os << "
"; GCLock lock; HtmlDocOutput::DocItem di(vdi->e()->type().ispar() ? HtmlDocOutput::DocItem::T_PAR: HtmlDocOutput::DocItem::T_VAR, sig, sig, os.str()); HtmlDocOutput::addToGroup(_maingroup, group, di); } } /// Visit function item void vFunctionI(FunctionI* fi) { if (Call* docstring = Expression::dyn_cast(getAnnotation(fi->ann(), constants().ann.doc_comment))) { std::string ds = eval_string(env,docstring->arg(0)); std::string group("main"); size_t group_idx = ds.find("@group"); if (group_idx!=std::string::npos) { group = HtmlDocOutput::extractArgWord(ds, group_idx); } size_t param_idx = ds.find("@param"); std::vector > params; while (param_idx != std::string::npos) { params.push_back(extractArgLine(ds, param_idx)); param_idx = ds.find("@param"); } std::vector args = replaceArgs(ds); std::unordered_set allArgs; for (unsigned int i=0; iparams().size(); i++) { if (allArgs.find(fi->params()[i]->id()->str().str()) == allArgs.end()) { std::cerr << "Warning: parameter " << *fi->params()[i]->id() << " not documented for function " << fi->id() << " at location " << fi->loc() << "\n"; } } std::string sig; { GCLock lock; FunctionI* fi_c = new FunctionI(Location(),fi->id(),fi->ti(),fi->params()); std::ostringstream oss_sig; oss_sig << *fi_c; sig = oss_sig.str(); sig.resize(sig.size()-2); } std::ostringstream os; os << "
\n"; os << "
"; os << ""; std::ostringstream fs; if (fi->ti()->type() == Type::ann()) { fs << "annotation "; os << "annotation "; } else if (fi->ti()->type() == Type::parbool()) { fs << "test "; os << "test "; } else if (fi->ti()->type() == Type::varbool()) { fs << "predicate "; os << "predicate "; } else { fs << "function " << *fi->ti() << ": "; os << "function " << *fi->ti() << ": "; } fs << fi->id() << "("; os << "" << fi->id() << "("; size_t align = fs.str().size(); for (unsigned int i=0; iparams().size(); i++) { fs << *fi->params()[i]->ti() << ": " << *fi->params()[i]->id(); if (i < fi->params().size()-1) { fs << ", "; } } bool splitArgs = (fs.str().size() > 70); for (unsigned int i=0; iparams().size(); i++) { os << "" << *fi->params()[i]->ti() << ": " << "" << *fi->params()[i]->id() << ""; if (i < fi->params().size()-1) { os << ","; if (splitArgs) { os << "\n"; for (unsigned int j=static_cast(align); j--;) os << " "; } else { os << " "; } } } os << ")"; if (fi->e()) { FunctionI* f_body = fi; bool alias; do { alias = false; Call* c = Expression::dyn_cast(f_body->e()); if (c && c->n_args()==f_body->params().size()) { bool sameParams = true; for (unsigned int i=0; iparams().size(); i++) { Id* ident = c->arg(i)->dyn_cast(); if (ident == NULL || ident->decl() != f_body->params()[i] || ident->str() != c->decl()->params()[i]->id()->str()) { sameParams = false; break; } } if (sameParams) { alias = true; f_body = c->decl(); } } } while (alias); if (f_body->e()) { std::ostringstream body_os; Printer p(body_os, 70); p.print(f_body->e()); std::string filename = f_body->loc().filename().str(); size_t lastSlash = filename.find_last_of("/"); if (lastSlash != std::string::npos) { filename = filename.substr(lastSlash+1, std::string::npos); } os << " ="; os << "\n
"; os << "
"; os << body_os.str(); os << "
\n"; os << "(standard decomposition from "<< filename << ":" << f_body->loc().first_line()<<")"; os << "
"; } } os << "
\n
\n"; if (fi->id().c_str()[0]=='\'') { std::string op = fi->id().str(); op = op.substr(1,op.length()-2); const char* space = (op[0]>='a' ? " " : ""); if (fi->params().size()==2) { os << "

Usage: " << *fi->params()[0]->id() << space << op << space << *fi->params()[1]->id() << "

"; } else if (fi->params().size()==1) { os << "

Usage: " << op << space << *fi->params()[0]->id() << "

"; } } std::string dshtml = addHTML(ds); os << dshtml; if (params.size() > 0) { os << "
Parameters
\n"; os << "
    \n"; for (unsigned int i=0; i" << params[i].first << ": " << params[i].second << "\n"; } os << "
\n"; } os << "
"; os << "
"; HtmlDocOutput::DocItem di(HtmlDocOutput::DocItem::T_FUN, fi->id().str(), sig, os.str()); HtmlDocOutput::addToGroup(_maingroup, group, di); } } }; std::vector HtmlPrinter::printHtml(EnvI& env, MiniZinc::Model* m, const std::string& basename, int splitLevel, bool includeStdLib, bool generateIndex) { using namespace HtmlDocOutput; Group g(basename,basename); FunMap funMap; CollectFunctionsVisitor fv(env,funMap,includeStdLib); iterItems(fv, m); PrintHtmlVisitor phv(env,g,funMap,includeStdLib); iterItems(phv, m); std::vector ret; struct SI { Group* g; Group* p; int level; int idx; SI(Group* g0, Group* p0, int level0, int idx0) : g(g0), p(p0), level(level0), idx(idx0) {} }; struct IndexEntry { std::string id; std::string sig; std::string link; std::string groupName; IndexEntry(const std::string& id0, const std::string& sig0, const std::string& link0, const std::string& groupName0) : id(id0), sig(sig0), link(link0), groupName(groupName0) { size_t spacepos = id.find_last_of(' '); if (spacepos != std::string::npos) { id = id.substr(spacepos+1); } } bool operator<(const IndexEntry& e) const { if (!isalpha(id[0]) && isalpha(e.id[0])) return true; return id == e.id ? groupName < e.groupName : id < e.id; } }; std::vector index; std::vector stack; stack.push_back(SI(&g,NULL,0,0)); while (!stack.empty()) { Group& g = *stack.back().g; int curLevel = stack.back().level; int curIdx = stack.back().idx; Group* p = stack.back().p; stack.pop_back(); for (auto it : g.items) { index.push_back(IndexEntry(it.id,it.sig,g.fullPath,g.htmlName)); } ret.push_back(HtmlDocument(g.fullPath, g.htmlName, g.toHTML(curLevel, splitLevel, p, curIdx, basename, generateIndex))); if (curLevel < splitLevel) { for (unsigned int i=0; i idxSections; if (index.size() != 0) { if (isalpha(index[0].id[0])) { char idxSec_c = (char)toupper(index[0].id[0]); std::string idxSec(&idxSec_c,1); oss << "

" << idxSec << "

\n"; idxSections.push_back(idxSec); } else { oss << "

Symbols

\n"; idxSections.push_back("Symbols"); } } oss << "
    \n"; std::string prevId = index.size()==0 ? "" : index[0].id; std::vector curEntries; for (auto ie : index) { if (ie.id != prevId) { oss << "
  • "; assert(curEntries.size() != 0); IndexEntry& cur = curEntries[0]; if (curEntries.size()==1) { oss << cur.id << " " << "(" << cur.groupName << ")"; } else { oss << cur.id << " ("; bool first = true; for (auto i_ie: curEntries) { if (first) { first = false; } else { oss << ", "; } oss << ""; oss << i_ie.groupName << ""; } oss << ")"; } oss << "
  • \n"; curEntries.clear(); } if (isalpha(ie.id[0]) && ie.id[0] != prevId[0]) { char idxSec_c = (char)toupper(ie.id[0]); std::string idxSec(&idxSec_c,1); oss << "
\n

" << idxSec << "

    "; idxSections.push_back(idxSec); } prevId = ie.id; if (curEntries.size()==0 || curEntries.back().groupName != ie.groupName) { curEntries.push_back(ie); } } oss << "
\n"; std::ostringstream oss_header; oss_header << "
\n"; oss_header << "
"; oss_header << " "; bool first = true; for (auto is : idxSections) { if (first) { first = false; } else { oss_header << " | "; } oss_header << "" << is << ""; } oss_header << "
"; oss_header << "
Index
\n"; HtmlDocument idx("doc-index", "Index", oss_header.str()+oss.str()); ret.push_back(idx); } return ret; } class PrintRSTVisitor : public ItemVisitor { protected: EnvI& env; HtmlDocOutput::Group& _maingroup; HtmlDocOutput::FunMap& _funmap; bool _includeStdLib; std::vector replaceArgsRST(std::string& s) { std::vector replacements; std::ostringstream oss; size_t lastpos = 0; size_t pos = std::min(s.find("\\a"), s.find("\\p")); size_t mathjax_open = s.find("\\("); size_t mathjax_close = s.rfind("\\)"); while (pos != std::string::npos) { oss << s.substr(lastpos, pos-lastpos); size_t start = pos; while (start < s.size() && s[start]!=' ' && s[start]!='\t') start++; while (start < s.size() && (s[start]==' ' || s[start]=='\t')) start++; size_t end = start+1; while (end < s.size() && (isalnum(s[end]) || s[end]=='_')) end++; bool needSpace = pos != 0 && s[pos-1] != ' ' && s[pos-1] != '\n'; if (s[pos+1]=='a') { replacements.push_back(s.substr(start,end-start)); if (pos >= mathjax_open && pos <= mathjax_close) { oss << "{\\bf " << replacements.back() << "}"; } else { oss << (needSpace ? " " : "") << "``" << replacements.back() << "`` "; } } else { if (pos >= mathjax_open && pos <= mathjax_close) { oss << "{\\bf " << s.substr(start,end-start) << "}"; } else { oss << (needSpace ? " " : "") << "``" << s.substr(start,end-start) << "`` "; } } lastpos = end; pos = std::min(s.find("\\a", lastpos), s.find("\\p", lastpos)); } oss << s.substr(lastpos, std::string::npos); s = oss.str(); std::ostringstream oss2; pos = std::min(s.find("\\("), s.find("\\)")); lastpos = 0; while (pos != std::string::npos) { if (s[pos+1]==')') { // remove trailing whitespace std::string t = s.substr(lastpos, pos-lastpos); size_t t_end = t.find_last_not_of(" "); if (t_end != std::string::npos) t_end++; oss2 << t.substr(0, t_end); } else { oss2 << s.substr(lastpos, pos-lastpos); } lastpos = pos+2; if (s[pos+1]=='(') { oss2 << ":math:`"; lastpos = s.find_first_not_of(" ", lastpos); } else { oss2 << "`"; } pos = std::min(s.find("\\(", lastpos), s.find("\\)", lastpos)); } oss2 << s.substr(lastpos, std::string::npos); s = oss2.str(); std::ostringstream oss3; pos = std::min(s.find("\\["), s.find("\\]")); lastpos = 0; while (pos != std::string::npos) { if (s[pos+1]==']') { // remove trailing whitespace std::string t = s.substr(lastpos, pos-lastpos); size_t t_end = t.find_last_not_of(" "); if (t_end != std::string::npos) t_end++; oss3 << t.substr(0, t_end); } else { oss3 << s.substr(lastpos, pos-lastpos); } lastpos = pos+2; if (s[pos+1]=='[') { oss3 << "``"; lastpos = s.find_first_not_of(" ", lastpos); } else { oss3 << "``"; } pos = std::min(s.find("\\[", lastpos), s.find("\\]", lastpos)); } oss3 << s.substr(lastpos, std::string::npos); s = oss3.str(); return replacements; } std::pair extractArgLine(std::string& s, size_t n) { size_t start = n; while (start < s.size() && s[start]!=' ' && s[start]!='\t') start++; while (start < s.size() && (s[start]==' ' || s[start]=='\t')) start++; size_t end = start+1; while (end < s.size() && s[end]!=':') end++; std::string arg = s.substr(start,end-start); size_t doc_start = end+1; while (end < s.size() && s[end]!='\n') end++; std::string ret = s.substr(doc_start,end-doc_start); replaceArgsRST(ret); s = s.substr(0,n)+s.substr(end,std::string::npos); return make_pair(arg,ret); } public: PrintRSTVisitor(EnvI& env0, HtmlDocOutput::Group& mg, HtmlDocOutput::FunMap& fm, bool includeStdLib) : env(env0), _maingroup(mg), _funmap(fm), _includeStdLib(includeStdLib) {} bool enterModel(Model* m) { if (!_includeStdLib && m->filename()=="stdlib.mzn") return false; const std::string& dc = m->docComment(); if (!dc.empty()) { size_t gpos = dc.find("@groupdef"); while (gpos != std::string::npos) { size_t start = gpos; while (start < dc.size() && dc[start]!=' ' && dc[start]!='\t') start++; while (start < dc.size() && (dc[start]==' ' || dc[start]=='\t')) start++; size_t end = start+1; while (end < dc.size() && (isalnum(dc[end]) || dc[end]=='_' || dc[end]=='.')) end++; std::string groupName = dc.substr(start,end-start); size_t doc_start = end+1; while (end < dc.size() && dc[end]!='\n') end++; std::string groupHTMLName = dc.substr(doc_start,end-doc_start); size_t next = dc.find("@groupdef", gpos+1); std::string groupDesc = dc.substr(end, next == std::string::npos ? next : next-end); replaceArgsRST(groupDesc); HtmlDocOutput::setGroupDesc(_maingroup, groupName, groupHTMLName, groupDesc); gpos = next; } } return true; } /// Visit variable declaration void vVarDeclI(VarDeclI* vdi) { if (Call* docstring = Expression::dyn_cast(getAnnotation(vdi->e()->ann(), constants().ann.doc_comment))) { std::string ds = eval_string(env,docstring->arg(0)); std::string group("main"); size_t group_idx = ds.find("@group"); if (group_idx!=std::string::npos) { group = HtmlDocOutput::extractArgWord(ds, group_idx); } std::ostringstream os; std::string sig = vdi->e()->type().toString(env)+" "+vdi->e()->id()->str().str(); std::string myMainGroup = group.substr(0,group.find_first_of(".")); auto it = _maingroup.subgroups.find(myMainGroup); os << ".. index::\n"; if (it != _maingroup.subgroups.m.end()) { os << " pair: " << (*it)->htmlName << "; " << *vdi->e()->id() << "\n\n"; } else { std::cerr << "did not find " << myMainGroup << "\n"; os << " single: " << *vdi->e()->id() << "\n\n"; } os << ".. code-block:: minizinc\n\n"; if (vdi->e()->ti()->type() == Type::ann()) { os << " annotation " << *vdi->e()->id(); } else { os << " " << *vdi->e()->ti() << ": " << *vdi->e()->id(); } os << "\n\n"; os << HtmlDocOutput::trim(ds) << "\n\n"; GCLock lock; HtmlDocOutput::DocItem di(vdi->e()->type().ispar() ? HtmlDocOutput::DocItem::T_PAR: HtmlDocOutput::DocItem::T_VAR, sig, sig, os.str()); HtmlDocOutput::addToGroup(_maingroup, group, di); } } /// Visit function item void vFunctionI(FunctionI* fi) { if (Call* docstring = Expression::dyn_cast(getAnnotation(fi->ann(), constants().ann.doc_comment))) { std::string ds = eval_string(env,docstring->arg(0)); std::string group("main"); size_t group_idx = ds.find("@group"); if (group_idx!=std::string::npos) { group = HtmlDocOutput::extractArgWord(ds, group_idx); } size_t param_idx = ds.find("@param"); std::vector > params; while (param_idx != std::string::npos) { params.push_back(extractArgLine(ds, param_idx)); param_idx = ds.find("@param"); } std::vector args = replaceArgsRST(ds); std::unordered_set allArgs; for (unsigned int i=0; iparams().size(); i++) { if (allArgs.find(fi->params()[i]->id()->str().str()) == allArgs.end()) { std::cerr << "Warning: parameter " << *fi->params()[i]->id() << " not documented for function " << fi->id() << " at location " << fi->loc() << "\n"; } } std::string sig; { GCLock lock; FunctionI* fi_c = new FunctionI(Location(),fi->id(),fi->ti(),fi->params()); std::ostringstream oss_sig; oss_sig << *fi_c; sig = oss_sig.str(); sig.resize(sig.size()-2); } std::ostringstream os; std::ostringstream fs; std::string myMainGroup = group.substr(0,group.find_first_of(".")); auto it = _maingroup.subgroups.find(myMainGroup); os << ".. index::\n"; if (it != _maingroup.subgroups.m.end()) { os << " pair: " << (*it)->htmlName << "; " << fi->id() << "\n\n"; } else { std::cerr << "did not find " << myMainGroup << "\n"; os << " single: " << fi->id() << "\n\n"; } os << ".. code-block:: minizinc\n\n"; if (fi->ti()->type() == Type::ann()) { fs << "annotation "; } else if (fi->ti()->type() == Type::parbool()) { fs << "test "; } else if (fi->ti()->type() == Type::varbool()) { fs << "predicate "; } else { fs << "function " << *fi->ti() << ": "; } fs << fi->id() << "("; os << " " << fs.str(); size_t align = fs.str().size(); for (unsigned int i=0; iparams().size(); i++) { fs << *fi->params()[i]->ti(); std::ostringstream fid; fid << *fi->params()[i]->id(); if (fid.str().size() != 0) fs << ": " << *fi->params()[i]->id(); if (i < fi->params().size()-1) { fs << ", "; } } bool splitArgs = (fs.str().size() > 70); for (unsigned int i=0; iparams().size(); i++) { os << *fi->params()[i]->ti(); std::ostringstream fid; fid << *fi->params()[i]->id(); if (fid.str().size() != 0) os << ": " << *fi->params()[i]->id(); if (i < fi->params().size()-1) { os << ","; if (splitArgs) { os << "\n "; for (unsigned int j=static_cast(align); j--;) os << " "; } else { os << " "; } } } os << ")"; os << "\n\n"; if (fi->id().c_str()[0]=='\'') { std::string op = fi->id().str(); op = op.substr(1,op.length()-2); if (fi->params().size()==2) { os << "Usage: ``" << *fi->params()[0]->id() << " " << op << " " << *fi->params()[1]->id() << "``\n\n"; } else if (fi->params().size()==1) { os << "Usage: ``" << op << " " << *fi->params()[0]->id() << "``\n\n"; } } os << HtmlDocOutput::trim(ds) << "\n\n"; if (fi->e()) { FunctionI* f_body = fi; bool alias; do { alias = false; Call* c = Expression::dyn_cast(f_body->e()); if (c && c->n_args()==f_body->params().size()) { bool sameParams = true; for (unsigned int i=0; iparams().size(); i++) { Id* ident = c->arg(i)->dyn_cast(); if (ident == NULL || ident->decl() != f_body->params()[i] || ident->str() != c->decl()->params()[i]->id()->str()) { sameParams = false; break; } } if (sameParams) { alias = true; f_body = c->decl(); } } } while (alias); if (f_body->e()) { std::string filename = f_body->loc().filename().str(); size_t filePos = filename.find("std/"); if (filePos != std::string::npos) { filePos += 4; os << ".. only:: builder_html\n\n"; os << " `More... loc().first_line() << "-L" << f_body->loc().last_line() << ">`__\n\n"; } } } if (params.size() > 0) { os << "Parameters:\n\n"; for (unsigned int i=0; iid().str(), sig, os.str()); HtmlDocOutput::addToGroup(_maingroup, group, di); } } }; std::vector RSTPrinter::printRST(EnvI& env, MiniZinc::Model* m, const std::string& basename, int splitLevel, bool includeStdLib, bool generateIndex) { using namespace HtmlDocOutput; Group g(basename,basename); FunMap funMap; CollectFunctionsVisitor fv(env,funMap,includeStdLib); iterItems(fv, m); PrintRSTVisitor prv(env,g,funMap,includeStdLib); iterItems(prv, m); std::vector ret; std::ostringstream oss; oss << Group::rstHeading(g.htmlName, 0); oss << trim(g.desc) << "\n"; oss << ".. toctree::\n\n"; for (auto sg : g.subgroups.m) { oss << " " << sg->fullPath << "\n"; } ret.push_back(HtmlDocument(g.fullPath, g.htmlName, oss.str())); for (auto& sg : g.subgroups.m) { ret.push_back(HtmlDocument(sg->fullPath, sg->htmlName, sg->toRST(0))); } return ret; } } libminizinc-2.4.2/lib/json_parser.cpp000066400000000000000000000357161360574160400176470ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include using namespace std; namespace MiniZinc { class JSONParser::Token { public: TokenT t; protected: Token(TokenT t0) : t(t0) {} public: Token(void) : t(T_EOF) {} std::string s; int i; double d; bool b; Token(std::string s0) : t(T_STRING), s(s0) {} Token(int i0) : t(T_INT), i(i0), d(i0) {} Token(double d0) : t(T_FLOAT), d(d0) {} Token(bool b0) : t(T_BOOL), i(b0), d(b0), b(b0) {} static Token listOpen() { return Token(T_LIST_OPEN); } static Token listClose() { return Token(T_LIST_CLOSE); } static Token objOpen() { return Token(T_OBJ_OPEN); } static Token objClose() { return Token(T_OBJ_CLOSE); } static Token comma() { return Token(T_COMMA); } static Token colon() { return Token(T_COLON); } static Token eof() { return Token(T_EOF); } static Token null() { return Token(T_NULL); } string toString(void) { switch (t) { case T_LIST_OPEN: return "["; case T_LIST_CLOSE: return "]"; case T_OBJ_OPEN: return "{"; case T_OBJ_CLOSE: return "}"; case T_COMMA: return ","; case T_COLON: return ":"; case T_STRING: return "\""+s+"\""; case T_INT: { std::stringstream ss; ss << i; return ss.str(); } case T_FLOAT: { std::stringstream ss; ss << d; return ss.str(); } case T_BOOL: return b ? "true" : "false"; case T_NULL: return "null"; case T_EOF: return "eof"; } } }; Location JSONParser::errLocation(void) const { Location loc(filename,line,column,line,column); return loc; } JSONParser::Token JSONParser::readToken(istream& is) { string result; char buf[1]; enum { S_NOTHING, S_STRING, S_STRING_ESCAPE, S_INT, S_FLOAT } state; state = S_NOTHING; while (is.good()) { is.read(buf, sizeof(buf)); column += sizeof(buf); if (is.eof()) return Token::eof(); if (!is.good()) throw JSONError(env,errLocation(),"tokenization failed"); switch (state) { case S_NOTHING: switch (buf[0]) { case '\n': line++; column = 0; // fall through case ' ': case '\t': case '\r': break; case '[': return Token::listOpen(); case ']': return Token::listClose(); case '{': return Token::objOpen(); case '}': return Token::objClose(); case ',': return Token::comma(); case ':': return Token::colon(); case '"': result=""; state=S_STRING; break; case 't': { char rest[3]; is.read(rest,sizeof(rest)); column += sizeof(rest); if (!is.good() || std::strncmp(rest, "rue", 3) != 0) throw JSONError(env,errLocation(),"unexpected token `"+string(rest)+"'"); state = S_NOTHING; return Token(true); } break; case 'f': { char rest[4]; is.read(rest,sizeof(rest)); column += sizeof(rest); if (!is.good() || std::strncmp(rest, "alse", 4) != 0) throw JSONError(env,errLocation(),"unexpected token `"+string(rest)+"'"); state = S_NOTHING; return Token(false); } break; case 'n': { char rest[3]; is.read(rest,sizeof(rest)); column += sizeof(rest); if (!is.good() || std::strncmp(rest, "ull", 3) != 0) throw JSONError(env,errLocation(),"unexpected token `"+string(rest)+"'"); state = S_NOTHING; return Token::null(); } break; default: if ( (buf[0]>='0' && buf[0]<='9') || (buf[0]=='-') ) { result = buf[0]; state=S_INT; } else { throw JSONError(env,errLocation(),"unexpected token `"+string(1,buf[0])+"'"); } break; } break; case S_STRING_ESCAPE: switch (buf[0]) { case 'n': result += "\n"; break; case 't': result += "\t"; break; case '"': result += "\""; break; case '\\': result += "\\"; break; default: result += "\\"; result += buf[0]; break; } state = S_STRING; break; case S_STRING: if (buf[0]=='"') { state=S_NOTHING; return Token(result); } if (buf[0]=='\\') { state=S_STRING_ESCAPE; } else { result += buf[0]; } break; case S_INT: if (buf[0]=='.') { result += buf[0]; state=S_FLOAT; } else if (buf[0]>='0' && buf[0]<='9') { result += buf[0]; } else { is.unget(); std::istringstream iss(result); int v; iss >> v; state=S_NOTHING; return Token(v); } break; case S_FLOAT: if (buf[0]>='0' && buf[0]<='9') { result += buf[0]; } else { is.unget(); std::istringstream iss(result); double v; iss >> v; state=S_NOTHING; return Token(v); } break; } } throw JSONError(env,errLocation(),"unexpected token `"+string(result)+"'"); } void JSONParser::expectToken(istream& is, JSONParser::TokenT t) { Token rt = readToken(is); if (rt.t != t) { throw JSONError(env,errLocation(),"unexpected token"); } } string JSONParser::expectString(istream& is) { Token rt = readToken(is); if (rt.t != T_STRING) { throw JSONError(env,errLocation(),"unexpected token, expected string"); } return rt.s; } JSONParser::Token JSONParser::parseEnumString(istream& is) { Token next = readToken(is); if (next.t != T_STRING) { throw JSONError(env,errLocation(),"invalid enum object"); } if (next.s.empty()) { throw JSONError(env,errLocation(),"invalid enum identifier"); } size_t nonIdChar = next.s.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"); size_t nonIdBegin = next.s.find_first_of("0123456789_"); if (nonIdChar!=std::string::npos || nonIdBegin==0) { next.s = "'"+next.s+"'"; } return next; } Expression* JSONParser::parseObject(istream& is) { // precondition: found T_OBJ_OPEN Token objid = readToken(is); if (objid.t != T_STRING) throw JSONError(env,errLocation(),"invalid object"); expectToken(is, T_COLON); if (objid.s == "set") { expectToken(is, T_LIST_OPEN); vector elems; TokenT listT = T_COLON; // dummy marker for (Token next = readToken(is); next.t != T_LIST_CLOSE; next = readToken(is)) { switch (next.t) { case T_COMMA: break; case T_INT: if (listT==T_STRING || listT==T_OBJ_OPEN) throw JSONError(env,errLocation(),"invalid set literal"); if (listT!=T_FLOAT) listT = T_INT; elems.push_back(next); break; case T_FLOAT: if (listT==T_STRING || listT==T_OBJ_OPEN) throw JSONError(env,errLocation(),"invalid set literal"); listT = T_FLOAT; elems.push_back(next); break; case T_STRING: if (listT!=T_COLON && listT!=T_STRING) throw JSONError(env,errLocation(),"invalid set literal"); listT = T_STRING; elems.push_back(next); break; case T_BOOL: if (listT==T_STRING || listT==T_OBJ_OPEN) throw JSONError(env,errLocation(),"invalid set literal"); if (listT==T_COLON) listT = T_BOOL; elems.push_back(next); break; case T_OBJ_OPEN: { if (listT!=T_COLON && listT!=T_OBJ_OPEN) throw JSONError(env,errLocation(),"invalid set literal"); listT = T_OBJ_OPEN; Token enumid = readToken(is); if (enumid.t != T_STRING || enumid.s != "e") throw JSONError(env,errLocation(),"invalid enum object"); expectToken(is, T_COLON); Token next = parseEnumString(is); expectToken(is, T_OBJ_CLOSE); elems.push_back(next); break; } default: throw JSONError(env,errLocation(),"invalid set literal"); } } expectToken(is, T_OBJ_CLOSE); vector elems_e(elems.size()); switch (listT) { case T_COLON: break; case T_BOOL: for (unsigned int i=0; i exps; vector > dims; dims.emplace_back(1, 0); vector hadDim; hadDim.push_back(false); Token next; for (;;) { next = readToken(is); if (next.t!=T_LIST_OPEN) break; dims.emplace_back(1, 0); hadDim.push_back(false); } int curDim = static_cast(dims.size())-1; for (;;) { switch (next.t) { case T_LIST_CLOSE: hadDim[curDim] = true; curDim--; if (curDim<0) { goto list_done; } else if (!hadDim[curDim]) { dims[curDim].second++; } break; case T_LIST_OPEN: curDim++; break; case T_COMMA: break; case T_INT: if (!hadDim[curDim]) { dims[curDim].second++; } exps.push_back(IntLit::a(next.i)); break; case T_FLOAT: if (!hadDim[curDim]) { dims[curDim].second++; } exps.push_back(FloatLit::a(next.d)); break; case T_STRING: if (!hadDim[curDim]) { dims[curDim].second++; } exps.push_back(new StringLit(Location().introduce(),next.s)); break; case T_BOOL: if (!hadDim[curDim]) { dims[curDim].second++; } exps.push_back(new BoolLit(Location().introduce(),next.b)); break; case T_NULL: if (!hadDim[curDim]) { dims[curDim].second++; } exps.push_back(constants().absent); break; case T_OBJ_OPEN: if (!hadDim[curDim]) { dims[curDim].second++; } exps.push_back(parseObject(is)); break; default: throw JSONError(env,errLocation(),"cannot parse JSON file"); break; } next = readToken(is); } list_done: unsigned int expectedSize = 1; for (auto& d : dims) { expectedSize *= d.second; } if (exps.size() != expectedSize) { throw JSONError(env,errLocation(),"mismatch in array dimensions"); /// TODO: check each individual sub-array } return new ArrayLit(Location().introduce(),exps,dims); } Expression* JSONParser::parseExp(std::istream &is) { Token next = readToken(is); switch (next.t) { case T_INT: return IntLit::a(next.i); break; case T_FLOAT: return FloatLit::a(next.d); case T_STRING: return new StringLit(Location().introduce(),next.s); case T_BOOL: return new BoolLit(Location().introduce(),next.b); case T_NULL: return constants().absent; case T_OBJ_OPEN: return parseObject(is); case T_LIST_OPEN: return parseArray(is); default: throw JSONError(env,errLocation(),"cannot parse JSON file"); break; } } void JSONParser::parse(Model* m, std::istream& is) { line = 0; column = 0; expectToken(is, T_OBJ_OPEN); for (;;) { string ident = expectString(is); expectToken(is, T_COLON); Expression* e = parseExp(is); if (ident[0]!='_') { AssignI* ai = new AssignI(Location().introduce(),ident,e); m->addItem(ai); } Token next = readToken(is); if (next.t==T_OBJ_CLOSE) break; if (next.t!=T_COMMA) throw JSONError(env,errLocation(),"cannot parse JSON file"); } } void JSONParser::parse(Model* m, const std::string& filename0) { filename = filename0; ifstream is; is.open(filename, ios::in); if (!is.good()) { throw JSONError(env,Location().introduce(),"cannot open file "+filename); } parse(m,is); } void JSONParser::parseFromString(Model* m, const std::string& data) { istringstream iss(data); line = 0; column = 0; parse(m, iss); } namespace { bool isJSON(std::istream& is) { while (is.good()) { char c = is.get(); if (c=='{') return true; if (c!=' ' && c!='\n' && c!='\t' && c!='\r') return false; } return false; } } bool JSONParser::stringIsJSON(const std::string& data) { std::istringstream iss(data); return isJSON(iss); } bool JSONParser::fileIsJSON(const std::string& filename) { ifstream is; is.open(filename, ios::in); return isJSON(is); } } libminizinc-2.4.2/lib/lexer.lxx000066400000000000000000000366661360574160400164770ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ %option reentrant %option bison-bridge bison-locations %option noyywrap %option stack %{ #if defined __GNUC__ #pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wsign-compare" #pragma GCC diagnostic ignored "-Wdeprecated" #elif defined _MSC_VER #pragma warning(push, 1) #endif namespace MiniZinc{ class ParserLocation; } #define YYLTYPE MiniZinc::ParserLocation #define YYLTYPE_IS_DECLARED 1 #define YYLTYPE_IS_TRIVIAL 0 #include namespace MiniZinc { int utf8len(const char* s) { int l=0; for (int i=0; s[i] != '\0'; i++) if ((s[i] & 0xc0) != 0x80) l++; return l; } int yy_input_proc(char* buf, int size, yyscan_t yyscanner); } #define YY_INPUT(buf, result, max_size) \ result = ::MiniZinc::yy_input_proc(buf, max_size, yyscanner); #define YY_USER_ACTION \ { MiniZinc::ParserState* parm = \ static_cast(yyget_extra(yyscanner)); \ yylloc->first_line(yylloc->last_line()); \ yylloc->first_column(yylloc->last_column()+1); \ if(parm->hadNewline) { \ parm->hadNewline=false; \ parm->lineStartPos += parm->nTokenNextStart; \ parm->nTokenNextStart=1; \ yylloc->last_line(yylloc->last_line()+1); \ yylloc->first_line(yylloc->last_line()); \ yylloc->first_column(1); \ } \ if(yytext[0] == '\n') { \ parm->hadNewline=true; \ parm->nTokenNextStart+=0; \ } else { \ parm->nTokenNextStart+=yyleng; \ } \ yylloc->last_column(yylloc->first_column()+::MiniZinc::utf8len(yytext)-1); \ } namespace MiniZinc { bool hexstrtointval(const char* s, long long int& v) { std::istringstream iss(s); iss >> std::hex >> v; return !iss.fail(); } bool octstrtointval(const char* s, long long int& v) { std::istringstream iss(s); iss >> std::oct >> v; return !iss.fail(); } bool fast_strtointval(const char* s, long long int& v) { MiniZinc::IntVal x = 0; try { for (; *s != '\0'; ++s) { x = (x*10) + (*s - '0'); } } catch (MiniZinc::ArithmeticError&) { return false; } v = x.toInt(); return true; } bool strtofloatval(const char* s, double& v) { std::istringstream iss(s); iss >> v; return !iss.fail(); } void clearBuffer(void* parm) { MiniZinc::ParserState* pp = static_cast(parm); pp->stringBuffer = ""; } void appendBufferString(void* parm, const char* s) { MiniZinc::ParserState* pp = static_cast(parm); pp->stringBuffer += s; } void appendBufferChar(void* parm, char s) { MiniZinc::ParserState* pp = static_cast(parm); pp->stringBuffer += s; } char* bufferData(void* parm) { MiniZinc::ParserState* pp = static_cast(parm); return strdup(pp->stringBuffer.c_str()); } } %} %x string %x string_quote %x multilinecomment %x doccomment %x doccomment_file %s bracket_exp %s quoted_exp %% <*>\x0 { return MZN_INVALID_NULL; } \xa { } [ \f\xd\t] { /* ignore whitespace */ } "/**" { yy_push_state(doccomment,yyscanner); ::MiniZinc::clearBuffer(yyget_extra(yyscanner)); } { "*/" { yylval->sValue = ::MiniZinc::bufferData(yyget_extra(yyscanner)); yy_pop_state(yyscanner); return MZN_DOC_COMMENT; } [^*\xa]+ { ::MiniZinc::appendBufferString(yyget_extra(yyscanner), yytext); } "*" { ::MiniZinc::appendBufferString(yyget_extra(yyscanner), yytext); } \xa { ::MiniZinc::appendBufferString(yyget_extra(yyscanner), yytext); } } "/***" { yy_push_state(doccomment_file,yyscanner); ::MiniZinc::clearBuffer(yyget_extra(yyscanner)); } { "*/" { yylval->sValue = ::MiniZinc::bufferData(yyget_extra(yyscanner)); yy_pop_state(yyscanner); return MZN_DOC_FILE_COMMENT; } [^*\xa]+ { ::MiniZinc::appendBufferString(yyget_extra(yyscanner), yytext); } "*" { ::MiniZinc::appendBufferString(yyget_extra(yyscanner), yytext); } \xa { ::MiniZinc::appendBufferString(yyget_extra(yyscanner), yytext); } } "/*" { yy_push_state(multilinecomment,yyscanner); } { "*/" { yy_pop_state(yyscanner); } [^*\xa]+ { } "*" { } \xa { } } "[" { return MZN_LEFT_BRACKET; } "[|" { return MZN_LEFT_2D_BRACKET; } "]" { return MZN_RIGHT_BRACKET; } "|]" { return MZN_RIGHT_2D_BRACKET; } %[^\xa]* { /* ignore comments */ } "true" { yylval->iValue = 1; return MZN_BOOL_LITERAL; } "false" { yylval->iValue = 0; return MZN_BOOL_LITERAL; } 0[xX]([0-9a-fA-F]*\.[0-9a-fA-F]+|[0-9a-fA-F]+\.)([pP][+-]?[0-9]+)|(0[xX][0-9a-fA-F]+[pP][+-]?[0-9]+) { if (::MiniZinc::strtofloatval(yytext, yylval->dValue)) return MZN_FLOAT_LITERAL; else return MZN_INVALID_FLOAT_LITERAL; } 0[xX][0-9A-Fa-f]+ { if (::MiniZinc::hexstrtointval(yytext+2, yylval->iValue)) return MZN_INTEGER_LITERAL; else return MZN_INVALID_INTEGER_LITERAL; } 0o[0-7]+ { if (::MiniZinc::octstrtointval(yytext+2, yylval->iValue)) return MZN_INTEGER_LITERAL; else return MZN_INVALID_INTEGER_LITERAL; } [0-9]+ { if (::MiniZinc::fast_strtointval(yytext, yylval->iValue)) return MZN_INTEGER_LITERAL; else return MZN_INVALID_INTEGER_LITERAL; } [0-9]+\.[0-9]+ { if (::MiniZinc::strtofloatval(yytext, yylval->dValue)) return MZN_FLOAT_LITERAL; else return MZN_INVALID_FLOAT_LITERAL; } [0-9]+\.[0-9]+[Ee][+-]?[0-9]+ { if (::MiniZinc::strtofloatval(yytext, yylval->dValue)) return MZN_FLOAT_LITERAL; else return MZN_INVALID_FLOAT_LITERAL; } [0-9]+[Ee][+-]?[0-9]+ { if (::MiniZinc::strtofloatval(yytext, yylval->dValue)) return MZN_FLOAT_LITERAL; else return MZN_INVALID_FLOAT_LITERAL; } [:;|{},\[\]\.] { return *yytext; } \.\. { return MZN_DOTDOT; } "'\.\.'" { return MZN_DOTDOT_QUOTED; } :: { return MZN_COLONCOLON; } _ { return MZN_UNDERSCORE; } "ann" { return MZN_ANN; } "annotation" { return MZN_ANNOTATION; } "any" { return MZN_ANY; } "array" { return MZN_ARRAY; } "bool" { return MZN_BOOL; } "case" { return MZN_CASE; } "constraint" { return MZN_CONSTRAINT; } "default" { return MZN_DEFAULT; } "div" { return MZN_IDIV; } "'div'" { return MZN_IDIV_QUOTED; } "diff" { return MZN_DIFF; } "'diff'" { return MZN_DIFF_QUOTED; } "else" { return MZN_ELSE; } "elseif" { return MZN_ELSEIF; } "endif" { return MZN_ENDIF; } "enum" { return MZN_ENUM; } "float" { return MZN_FLOAT; } "function" { return MZN_FUNCTION; } "if" { return MZN_IF; } "include" { return MZN_INCLUDE; } "infinity" { return MZN_INFINITY; } "intersect" { return MZN_INTERSECT; } "'intersect'" { return MZN_INTERSECT_QUOTED; } "in" { return MZN_IN; } "'in'" { return MZN_IN_QUOTED; } "int" { return MZN_INT; } "let" { return MZN_LET; } "list" { return MZN_LIST; } "maximize" { yylval->bValue = false; return MZN_MAXIMIZE; } "minimize" { yylval->bValue = true; return MZN_MINIMIZE; } "mod" { return MZN_MOD; } "'mod'" { return MZN_MOD_QUOTED; } "not" { return MZN_NOT; } "'not'" { return MZN_NOT_QUOTED; } "of" { return MZN_OF; } "output" { return MZN_OUTPUT; } "opt" { return MZN_OPT; } "par" { return MZN_PAR; } "predicate" { return MZN_PREDICATE; } "record" { return MZN_RECORD; } "satisfy" { return MZN_SATISFY; } "set" { return MZN_SET; } "solve" { return MZN_SOLVE; } "string" { return MZN_STRING; } "subset" { return MZN_SUBSET; } "'subset'" { return MZN_SUBSET_QUOTED; } "superset" { return MZN_SUPERSET; } "'superset'" { return MZN_SUPERSET_QUOTED; } "symdiff" { return MZN_SYMDIFF; } "'symdiff'" { return MZN_SYMDIFF_QUOTED; } "test" { return MZN_TEST; } "then" { return MZN_THEN; } "tuple" { return MZN_TUPLE; } "type" { return MZN_TYPE; } "union" { return MZN_UNION; } "'union'" { return MZN_UNION_QUOTED; } "var" { return MZN_VAR; } "variant_record" { return MZN_VARIANT_RECORD; } "where" { return MZN_WHERE; } "xor" { return MZN_XOR; } "'xor'" { return MZN_XOR_QUOTED; } "+" { return MZN_PLUS; } "'+'" { return MZN_PLUS_QUOTED; } "-" { return MZN_MINUS; } "'-'" { return MZN_MINUS_QUOTED; } "*" { return MZN_MULT; } "'*'" { return MZN_MULT_QUOTED; } "/" { return MZN_DIV; } "'/'" { return MZN_DIV_QUOTED; } "^" { return MZN_POW; } "'^'" { return MZN_POW_QUOTED; } "++" { return MZN_PLUSPLUS; } "'++'" { return MZN_PLUSPLUS_QUOTED; } "<>" { return MZN_ABSENT; } "<" { return MZN_LE; } "'<'" { return MZN_LE_QUOTED; } "<=" { return MZN_LQ; } "'<='" { return MZN_LQ_QUOTED; } ">" { return MZN_GR; } "'>'" { return MZN_GR_QUOTED; } ">=" { return MZN_GQ; } "'>='" { return MZN_GQ_QUOTED; } "==" { return MZN_EQ; } "'=='" { return MZN_EQ_QUOTED; } "=" { return MZN_EQ; } "'='" { return MZN_EQ_QUOTED; } "!=" { return MZN_NQ; } "'!='" { return MZN_NQ_QUOTED; } "->" { return MZN_IMPL; } "'->'" { return MZN_IMPL_QUOTED; } "<-" { return MZN_RIMPL; } "'<-'" { return MZN_RIMPL_QUOTED; } "<->" { return MZN_EQUIV; } "'<->'" { return MZN_EQUIV_QUOTED; } "\\/" { return MZN_OR; } "'\\/'" { return MZN_OR_QUOTED; } "/\\" { return MZN_AND; } "'/\\'" { return MZN_AND_QUOTED; } "~+" { return MZN_WEAK_PLUS; } "~*" { return MZN_WEAK_MULT; } "~=" { return MZN_WEAK_EQ; } "~-" { return MZN_WEAK_MINUS; } "'~"[+*=-]"'" { yylval->sValue = strdup(yytext+1); yylval->sValue[strlen(yytext)-2] = 0; return MZN_IDENTIFIER; } "_objective" { yylval->sValue = strdup(yytext); return MZN_IDENTIFIER; } [A-Za-z][A-Za-z0-9_]* { yylval->sValue = strdup(yytext); return MZN_IDENTIFIER; } "'"[^\\'\xa\xd\x0]*"'" { yylval->sValue = strdup(yytext); return MZN_IDENTIFIER; } _[A-Za-z][A-Za-z0-9_]* { MiniZinc::ParserState* parm = static_cast(yyget_extra(yyscanner)); if (parm->isFlatZinc) { yylval->sValue = strdup(yytext); return MZN_IDENTIFIER; } else { return FLATZINC_IDENTIFIER; } } "\xE2\x88\x80" { yylval->sValue = strdup("forall"); return MZN_IDENTIFIER; } "\xE2\x88\x83" { yylval->sValue = strdup("exists"); return MZN_IDENTIFIER; } "\xE2\x88\x88" { return MZN_IN; } "\xE2\x8A\x86" { return MZN_SUBSET; } "\xE2\x8A\x87" { return MZN_SUPERSET; } "\xE2\x88\x9E" { return MZN_INFINITY; } "\xC2\xAC" { return MZN_NOT; } "\xE2\x86\x90" { return MZN_RIMPL; } "\xE2\x86\x92" { return MZN_IMPL; } "\xE2\x86\x94" { return MZN_EQUIV; } "\xE2\x88\xA7" { return MZN_AND; } "\xE2\x88\xA8" { return MZN_OR; } "\xE2\x89\xA0" { return MZN_NQ; } "\xE2\x89\xA4" { return MZN_LQ; } "\xE2\x89\xA5" { return MZN_GQ; } "\xE2\x88\xAA" { return MZN_UNION; } "\xE2\x88\xA9" { return MZN_INTERSECT; } $$[A-Za-z][A-Za-z0-9_]* { yylval->sValue = strdup(yytext+1); return MZN_TI_ENUM_IDENTIFIER; } $[A-Za-z][A-Za-z0-9_]* { yylval->sValue = strdup(yytext+1); return MZN_TI_IDENTIFIER; } "(" { yy_push_state(bracket_exp,yyscanner); return *yytext; } ")" { yy_pop_state(yyscanner); return *yytext; } ")" { yy_pop_state(yyscanner); yy_pop_state(yyscanner); yy_push_state(string_quote,yyscanner); ::MiniZinc::clearBuffer(yyget_extra(yyscanner)); } \" { yy_push_state(string,yyscanner); ::MiniZinc::clearBuffer(yyget_extra(yyscanner)); } [^\\"\xa\xd\x0]* { ::MiniZinc::appendBufferString(yyget_extra(yyscanner), yytext); } \\n { ::MiniZinc::appendBufferChar(yyget_extra(yyscanner), '\n'); } \\t { ::MiniZinc::appendBufferChar(yyget_extra(yyscanner), '\t'); } \\[\\'] { ::MiniZinc::appendBufferChar(yyget_extra(yyscanner), yytext[1]); } \\[\\"] { ::MiniZinc::appendBufferChar(yyget_extra(yyscanner), yytext[1]); } \\"(" { yylval->sValue = ::MiniZinc::bufferData(yyget_extra(yyscanner)); yy_push_state(quoted_exp,yyscanner); return MZN_STRING_QUOTE_START; } \\"(" { yylval->sValue = ::MiniZinc::bufferData(yyget_extra(yyscanner)); yy_push_state(quoted_exp,yyscanner); return MZN_STRING_QUOTE_MID; } \" { yylval->sValue = ::MiniZinc::bufferData(yyget_extra(yyscanner)); yy_pop_state(yyscanner); return MZN_STRING_LITERAL; } \" { yylval->sValue = ::MiniZinc::bufferData(yyget_extra(yyscanner)); yy_pop_state(yyscanner); return MZN_STRING_QUOTE_END; } . { return (unsigned char)yytext[0]; } [\xa\xd\x0] { return MZN_END_OF_LINE_IN_STRING; } <> { yy_pop_state(yyscanner); return MZN_UNTERMINATED_STRING; } `[A-Za-z][A-Za-z0-9_]*` { yylval->sValue = strdup(yytext+1); yylval->sValue[strlen(yytext)-2] = 0; return MZN_QUOTED_IDENTIFIER; } . { return (unsigned char)yytext[0]; } %% namespace MiniZinc { int yy_input_proc(char* buf, int size, yyscan_t yyscanner) { MiniZinc::ParserState* parm = static_cast(yyget_extra(yyscanner)); return parm->fillBuffer(buf, size); // work around warning that yyunput is unused yyunput (0,buf,yyscanner); } } libminizinc-2.4.2/lib/miniz.c000066400000000000000000011441551360574160400161070ustar00rootroot00000000000000/************************************************************************** * * Copyright 2013-2014 RAD Game Tools and Valve Software * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * **************************************************************************/ #include typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; #ifdef __cplusplus extern "C" { #endif /* ------------------- zlib-style API's */ mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) { mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552; if (!ptr) return MZ_ADLER32_INIT; while (buf_len) { for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; } for (; i < block_len; ++i) s1 += *ptr++, s2 += s1; s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; } return (s2 << 16) + s1; } /* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ */ #if 0 mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) { static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; mz_uint32 crcu32 = (mz_uint32)crc; if (!ptr) return MZ_CRC32_INIT; crcu32 = ~crcu32; while (buf_len--) { mz_uint8 b = *ptr++; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; } return ~crcu32; } #else /* Faster, but larger CPU cache footprint. */ mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) { static const mz_uint32 s_crc_table[256] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; while (buf_len >= 4) { crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; pByte_buf += 4; buf_len -= 4; } while (buf_len) { crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; ++pByte_buf; --buf_len; } return ~crc32; } #endif void mz_free(void *p) { MZ_FREE(p); } void *miniz_def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque, (void)items, (void)size; return MZ_MALLOC(items * size); } void miniz_def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); } void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) { (void)opaque, (void)address, (void)items, (void)size; return MZ_REALLOC(address, items * size); } const char *mz_version(void) { return MZ_VERSION; } #ifndef MINIZ_NO_ZLIB_APIS int mz_deflateInit(mz_streamp pStream, int level) { return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); } int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) { tdefl_compressor *pComp; mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); if (!pStream) return MZ_STREAM_ERROR; if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) return MZ_PARAM_ERROR; pStream->data_type = 0; pStream->adler = MZ_ADLER32_INIT; pStream->msg = NULL; pStream->reserved = 0; pStream->total_in = 0; pStream->total_out = 0; if (!pStream->zalloc) pStream->zalloc = miniz_def_alloc_func; if (!pStream->zfree) pStream->zfree = miniz_def_free_func; pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); if (!pComp) return MZ_MEM_ERROR; pStream->state = (struct mz_internal_state *)pComp; if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) { mz_deflateEnd(pStream); return MZ_PARAM_ERROR; } return MZ_OK; } int mz_deflateReset(mz_streamp pStream) { if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR; pStream->total_in = pStream->total_out = 0; tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); return MZ_OK; } int mz_deflate(mz_streamp pStream, int flush) { size_t in_bytes, out_bytes; mz_ulong orig_total_in, orig_total_out; int mz_status = MZ_OK; if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return MZ_STREAM_ERROR; if (!pStream->avail_out) return MZ_BUF_ERROR; if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; if (((tdefl_compressor *)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; orig_total_in = pStream->total_in; orig_total_out = pStream->total_out; for (;;) { tdefl_status defl_status; in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; defl_status = tdefl_compress((tdefl_compressor *)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state); pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; if (defl_status < 0) { mz_status = MZ_STREAM_ERROR; break; } else if (defl_status == TDEFL_STATUS_DONE) { mz_status = MZ_STREAM_END; break; } else if (!pStream->avail_out) break; else if ((!pStream->avail_in) && (flush != MZ_FINISH)) { if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) break; return MZ_BUF_ERROR; /* Can't make forward progress without some input. */ } } return mz_status; } int mz_deflateEnd(mz_streamp pStream) { if (!pStream) return MZ_STREAM_ERROR; if (pStream->state) { pStream->zfree(pStream->opaque, pStream->state); pStream->state = NULL; } return MZ_OK; } mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) { (void)pStream; /* This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) */ return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); } int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) { int status; mz_stream stream; memset(&stream, 0, sizeof(stream)); /* In case mz_ulong is 64-bits (argh I hate longs). */ if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; stream.next_in = pSource; stream.avail_in = (mz_uint32)source_len; stream.next_out = pDest; stream.avail_out = (mz_uint32)*pDest_len; status = mz_deflateInit(&stream, level); if (status != MZ_OK) return status; status = mz_deflate(&stream, MZ_FINISH); if (status != MZ_STREAM_END) { mz_deflateEnd(&stream); return (status == MZ_OK) ? MZ_BUF_ERROR : status; } *pDest_len = stream.total_out; return mz_deflateEnd(&stream); } int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) { return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); } mz_ulong mz_compressBound(mz_ulong source_len) { return mz_deflateBound(NULL, source_len); } typedef struct { tinfl_decompressor m_decomp; mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits; mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; tinfl_status m_last_status; } inflate_state; int mz_inflateInit2(mz_streamp pStream, int window_bits) { inflate_state *pDecomp; if (!pStream) return MZ_STREAM_ERROR; if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR; pStream->data_type = 0; pStream->adler = 0; pStream->msg = NULL; pStream->total_in = 0; pStream->total_out = 0; pStream->reserved = 0; if (!pStream->zalloc) pStream->zalloc = miniz_def_alloc_func; if (!pStream->zfree) pStream->zfree = miniz_def_free_func; pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); if (!pDecomp) return MZ_MEM_ERROR; pStream->state = (struct mz_internal_state *)pDecomp; tinfl_init(&pDecomp->m_decomp); pDecomp->m_dict_ofs = 0; pDecomp->m_dict_avail = 0; pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; pDecomp->m_first_call = 1; pDecomp->m_has_flushed = 0; pDecomp->m_window_bits = window_bits; return MZ_OK; } int mz_inflateInit(mz_streamp pStream) { return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); } int mz_inflate(mz_streamp pStream, int flush) { inflate_state *pState; mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; size_t in_bytes, out_bytes, orig_avail_in; tinfl_status status; if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; pState = (inflate_state *)pStream->state; if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; orig_avail_in = pStream->avail_in; first_call = pState->m_first_call; pState->m_first_call = 0; if (pState->m_last_status < 0) return MZ_DATA_ERROR; if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; pState->m_has_flushed |= (flush == MZ_FINISH); if ((flush == MZ_FINISH) && (first_call)) { /* MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. */ decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); pState->m_last_status = status; pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; if (status < 0) return MZ_DATA_ERROR; else if (status != TINFL_STATUS_DONE) { pState->m_last_status = TINFL_STATUS_FAILED; return MZ_BUF_ERROR; } return MZ_STREAM_END; } /* flush != MZ_FINISH then we must assume there's more input. */ if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; if (pState->m_dict_avail) { n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; } for (;;) { in_bytes = pStream->avail_in; out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); pState->m_last_status = status; pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); pState->m_dict_avail = (mz_uint)out_bytes; n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); if (status < 0) return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */ else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */ else if (flush == MZ_FINISH) { /* The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. */ if (status == TINFL_STATUS_DONE) return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. */ else if (!pStream->avail_out) return MZ_BUF_ERROR; } else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) break; } return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; } int mz_inflateEnd(mz_streamp pStream) { if (!pStream) return MZ_STREAM_ERROR; if (pStream->state) { pStream->zfree(pStream->opaque, pStream->state); pStream->state = NULL; } return MZ_OK; } int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) { mz_stream stream; int status; memset(&stream, 0, sizeof(stream)); /* In case mz_ulong is 64-bits (argh I hate longs). */ if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; stream.next_in = pSource; stream.avail_in = (mz_uint32)source_len; stream.next_out = pDest; stream.avail_out = (mz_uint32)*pDest_len; status = mz_inflateInit(&stream); if (status != MZ_OK) return status; status = mz_inflate(&stream, MZ_FINISH); if (status != MZ_STREAM_END) { mz_inflateEnd(&stream); return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; } *pDest_len = stream.total_out; return mz_inflateEnd(&stream); } const char *mz_error(int err) { static struct { int m_err; const char *m_pDesc; } s_error_descs[] = { { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } }; mz_uint i; for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc; return NULL; } #endif /*MINIZ_NO_ZLIB_APIS */ #ifdef __cplusplus } #endif /* This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to */ /************************************************************************** * * Copyright 2013-2014 RAD Game Tools and Valve Software * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * **************************************************************************/ #ifdef __cplusplus extern "C" { #endif /* ------------------- Low-level Compression (independent from all decompression API's) */ /* Purposely making these tables static for faster init and thread safety. */ static const mz_uint16 s_tdefl_len_sym[256] = { 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285 }; static const mz_uint8 s_tdefl_len_extra[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0 }; static const mz_uint8 s_tdefl_small_dist_sym[512] = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17 }; static const mz_uint8 s_tdefl_small_dist_extra[512] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 }; static const mz_uint8 s_tdefl_large_dist_sym[128] = { 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 }; static const mz_uint8 s_tdefl_large_dist_extra[128] = { 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13 }; /* Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. */ typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq; static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms1) { mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; MZ_CLEAR_OBJ(hist); for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; } while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--; for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) { const mz_uint32 *pHist = &hist[pass << 8]; mz_uint offsets[256], cur_ofs = 0; for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; } for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; { tdefl_sym_freq *t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; } } return pCur_syms; } /* tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. */ static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) { int root, leaf, next, avbl, used, dpth; if (n == 0) return; else if (n == 1) { A[0].m_key = 1; return; } A[0].m_key += A[1].m_key; root = 0; leaf = 2; for (next = 1; next < n - 1; next++) { if (leaf >= n || A[root].m_key < A[leaf].m_key) { A[next].m_key = A[root].m_key; A[root++].m_key = (mz_uint16)next; } else A[next].m_key = A[leaf++].m_key; if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) { A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); A[root++].m_key = (mz_uint16)next; } else A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); } A[n - 2].m_key = 0; for (next = n - 3; next >= 0; next--) A[next].m_key = A[A[next].m_key].m_key + 1; avbl = 1; used = dpth = 0; root = n - 2; next = n - 1; while (avbl > 0) { while (root >= 0 && (int)A[root].m_key == dpth) { used++; root--; } while (avbl > used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; } avbl = 2 * used; dpth++; used = 0; } } /* Limits canonical Huffman code table's max code size. */ enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) { int i; mz_uint32 total = 0; if (code_list_len <= 1) return; for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i]; for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); while (total != (1UL << max_code_size)) { pNum_codes[max_code_size]--; for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; } total--; } } static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) { int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; MZ_CLEAR_OBJ(num_codes); if (static_table) { for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++; } else { tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; int num_used_syms = 0; const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; for (i = 0; i < table_len; i++) if (pSym_count[i]) { syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; syms0[num_used_syms++].m_sym_index = (mz_uint16)i; } pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); for (i = 1, j = num_used_syms; i <= code_size_limit; i++) for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); } next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1); for (i = 0; i < table_len; i++) { mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1); d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; } } #define TDEFL_PUT_BITS(b, l) \ do \ { \ mz_uint bits = b; \ mz_uint len = l; \ MZ_ASSERT(bits <= ((1U << len) - 1U)); \ d->m_bit_buffer |= (bits << d->m_bits_in); \ d->m_bits_in += len; \ while (d->m_bits_in >= 8) \ { \ if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ d->m_bit_buffer >>= 8; \ d->m_bits_in -= 8; \ } \ } \ MZ_MACRO_END #define TDEFL_RLE_PREV_CODE_SIZE() \ { \ if (rle_repeat_count) \ { \ if (rle_repeat_count < 3) \ { \ d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ while (rle_repeat_count--) \ packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ } \ else \ { \ d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \ packed_code_sizes[num_packed_code_sizes++] = 16; \ packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ } \ rle_repeat_count = 0; \ } \ } #define TDEFL_RLE_ZERO_CODE_SIZE() \ { \ if (rle_z_count) \ { \ if (rle_z_count < 3) \ { \ d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \ while (rle_z_count--) \ packed_code_sizes[num_packed_code_sizes++] = 0; \ } \ else if (rle_z_count <= 10) \ { \ d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \ packed_code_sizes[num_packed_code_sizes++] = 17; \ packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ } \ else \ { \ d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \ packed_code_sizes[num_packed_code_sizes++] = 18; \ packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ } \ rle_z_count = 0; \ } \ } static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; static void tdefl_start_dynamic_block(tdefl_compressor *d) { int num_lit_codes, num_dist_codes, num_bit_lengths; mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; d->m_huff_count[0][256] = 1; tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break; for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break; memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0; memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); for (i = 0; i < total_code_sizes_to_pack; i++) { mz_uint8 code_size = code_sizes_to_pack[i]; if (!code_size) { TDEFL_RLE_PREV_CODE_SIZE(); if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); } } else { TDEFL_RLE_ZERO_CODE_SIZE(); if (code_size != prev_code_size) { TDEFL_RLE_PREV_CODE_SIZE(); d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); packed_code_sizes[num_packed_code_sizes++] = code_size; } else if (++rle_repeat_count == 6) { TDEFL_RLE_PREV_CODE_SIZE(); } } prev_code_size = code_size; } if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } else { TDEFL_RLE_ZERO_CODE_SIZE(); } tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); TDEFL_PUT_BITS(2, 2); TDEFL_PUT_BITS(num_lit_codes - 257, 5); TDEFL_PUT_BITS(num_dist_codes - 1, 5); for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break; num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4); for (i = 0; (int)i < num_bit_lengths; i++) TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes;) { mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); } } static void tdefl_start_static_block(tdefl_compressor *d) { mz_uint i; mz_uint8 *p = &d->m_huff_code_sizes[0][0]; for (i = 0; i <= 143; ++i) *p++ = 8; for (; i <= 255; ++i) *p++ = 9; for (; i <= 279; ++i) *p++ = 7; for (; i <= 287; ++i) *p++ = 8; memset(d->m_huff_code_sizes[1], 5, 32); tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); TDEFL_PUT_BITS(1, 2); } static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { mz_uint flags; mz_uint8 *pLZ_codes; mz_uint8 *pOutput_buf = d->m_pOutput_buf; mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; mz_uint64 bit_buffer = d->m_bit_buffer; mz_uint bits_in = d->m_bits_in; #define TDEFL_PUT_BITS_FAST(b, l) \ { \ bit_buffer |= (((mz_uint64)(b)) << bits_in); \ bits_in += (l); \ } flags = 1; for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) { if (flags == 1) flags = *pLZ_codes++ | 0x100; if (flags & 1) { mz_uint s0, s1, n0, n1, sym, num_extra_bits; mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); pLZ_codes += 3; MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); /* This sequence coaxes MSVC into using cmov's vs. jmp's. */ s0 = s_tdefl_small_dist_sym[match_dist & 511]; n0 = s_tdefl_small_dist_extra[match_dist & 511]; s1 = s_tdefl_large_dist_sym[match_dist >> 8]; n1 = s_tdefl_large_dist_extra[match_dist >> 8]; sym = (match_dist < 512) ? s0 : s1; num_extra_bits = (match_dist < 512) ? n0 : n1; MZ_ASSERT(d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); } else { mz_uint lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { flags >>= 1; lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { flags >>= 1; lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); } } } if (pOutput_buf >= d->m_pOutput_buf_end) return MZ_FALSE; *(mz_uint64 *)pOutput_buf = bit_buffer; pOutput_buf += (bits_in >> 3); bit_buffer >>= (bits_in & ~7); bits_in &= 7; } #undef TDEFL_PUT_BITS_FAST d->m_pOutput_buf = pOutput_buf; d->m_bits_in = 0; d->m_bit_buffer = 0; while (bits_in) { mz_uint32 n = MZ_MIN(bits_in, 16); TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); bit_buffer >>= n; bits_in -= n; } TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); return (d->m_pOutput_buf < d->m_pOutput_buf_end); } #else static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { mz_uint flags; mz_uint8 *pLZ_codes; flags = 1; for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) { if (flags == 1) flags = *pLZ_codes++ | 0x100; if (flags & 1) { mz_uint sym, num_extra_bits; mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3; MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); if (match_dist < 512) { sym = s_tdefl_small_dist_sym[match_dist]; num_extra_bits = s_tdefl_small_dist_extra[match_dist]; } else { sym = s_tdefl_large_dist_sym[match_dist >> 8]; num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; } MZ_ASSERT(d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); } else { mz_uint lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); } } TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); return (d->m_pOutput_buf < d->m_pOutput_buf_end); } #endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS */ static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) { if (static_block) tdefl_start_static_block(d); else tdefl_start_dynamic_block(d); return tdefl_compress_lz_codes(d); } static int tdefl_flush_block(tdefl_compressor *d, int flush) { mz_uint saved_bit_buf, saved_bits_in; mz_uint8 *pSaved_output_buf; mz_bool comp_block_succeeded = MZ_FALSE; int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; d->m_pOutput_buf = pOutput_buf_start; d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; MZ_ASSERT(!d->m_output_flush_remaining); d->m_output_flush_ofs = 0; d->m_output_flush_remaining = 0; *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) { TDEFL_PUT_BITS(0x78, 8); TDEFL_PUT_BITS(0x01, 8); } TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in; if (!use_raw_block) comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); /* If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. */ if (((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) { mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; TDEFL_PUT_BITS(0, 2); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) { TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); } for (i = 0; i < d->m_total_lz_bytes; ++i) { TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); } } /* Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. */ else if (!comp_block_succeeded) { d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; tdefl_compress_block(d, MZ_TRUE); } if (flush) { if (flush == TDEFL_FINISH) { if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { mz_uint i, a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); a <<= 8; } } } else { mz_uint i, z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); } } } MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; d->m_total_lz_bytes = 0; d->m_block_index++; if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) { if (d->m_pPut_buf_func) { *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); } else if (pOutput_buf_start == d->m_output_buf) { int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); d->m_out_buf_ofs += bytes_to_copy; if ((n -= bytes_to_copy) != 0) { d->m_output_flush_ofs = bytes_to_copy; d->m_output_flush_remaining = n; } } else { d->m_out_buf_ofs += n; } } return d->m_output_flush_remaining; } #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES #ifdef MINIZ_UNALIGNED_USE_MEMCPY static inline mz_uint16 TDEFL_READ_UNALIGNED_WORD(const mz_uint8* p) { mz_uint16 ret; memcpy(&ret, p, sizeof(mz_uint16)); return ret; } static inline mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16* p) { mz_uint16 ret; memcpy(&ret, p, sizeof(mz_uint16)); return ret; } #else #define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p) #define TDEFL_READ_UNALIGNED_WORD2(p) *(const mz_uint16 *)(p) #endif static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD2(s); MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; for (;;) { for (;;) { if (--num_probes_left == 0) return; #define TDEFL_PROBE \ next_probe_pos = d->m_next[probe_pos]; \ if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ return; \ probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \ break; TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; } if (!dist) break; q = (const mz_uint16 *)(d->m_dict + probe_pos); if (TDEFL_READ_UNALIGNED_WORD2(q) != s01) continue; p = s; probe_len = 32; do { } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); if (!probe_len) { *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN); break; } else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q)) > match_len) { *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break; c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); } } } #else static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; const mz_uint8 *s = d->m_dict + pos, *p, *q; mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; for (;;) { for (;;) { if (--num_probes_left == 0) return; #define TDEFL_PROBE \ next_probe_pos = d->m_next[probe_pos]; \ if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ return; \ probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) \ break; TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; } if (!dist) break; p = s; q = d->m_dict + probe_pos; for (probe_len = 0; probe_len < max_match_len; probe_len++) if (*p++ != *q++) break; if (probe_len > match_len) { *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return; c0 = d->m_dict[pos + match_len]; c1 = d->m_dict[pos + match_len - 1]; } } } #endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */ #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN static mz_bool tdefl_compress_fast(tdefl_compressor *d) { /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */ mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) { const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); d->m_src_buf_left -= num_bytes_to_process; lookahead_size += num_bytes_to_process; while (num_bytes_to_process) { mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); memcpy(d->m_dict + dst_pos, d->m_pSrc, n); if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); d->m_pSrc += n; dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; num_bytes_to_process -= n; } dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break; while (lookahead_size >= 4) { mz_uint cur_match_dist, cur_match_len = 1; mz_uint8 *pCur_dict = d->m_dict + cur_pos; mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; mz_uint probe_pos = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)lookahead_pos; if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) { const mz_uint16 *p = (const mz_uint16 *)pCur_dict; const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); mz_uint32 probe_len = 32; do { } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); if (!probe_len) cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) { cur_match_len = 1; *pLZ_code_buf++ = (mz_uint8)first_trigram; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); d->m_huff_count[0][(mz_uint8)first_trigram]++; } else { mz_uint32 s0, s1; cur_match_len = MZ_MIN(cur_match_len, lookahead_size); MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); cur_match_dist--; pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; pLZ_code_buf += 3; *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; } } else { *pLZ_code_buf++ = (mz_uint8)first_trigram; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); d->m_huff_count[0][(mz_uint8)first_trigram]++; } if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } total_lz_bytes += cur_match_len; lookahead_pos += cur_match_len; dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; MZ_ASSERT(lookahead_size >= cur_match_len); lookahead_size -= cur_match_len; if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { int n; d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; } } while (lookahead_size) { mz_uint8 lit = d->m_dict[cur_pos]; total_lz_bytes++; *pLZ_code_buf++ = lit; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } d->m_huff_count[0][lit]++; lookahead_pos++; dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; lookahead_size--; if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { int n; d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; } } } d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; return MZ_TRUE; } #endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) { d->m_total_lz_bytes++; *d->m_pLZ_code_buf++ = lit; *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } d->m_huff_count[0][lit]++; } static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) { mz_uint32 s0, s1; MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); d->m_total_lz_bytes += match_len; d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); match_dist -= 1; d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3; *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; if (match_len >= TDEFL_MIN_MATCH_LEN) d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; } static mz_bool tdefl_compress_normal(tdefl_compressor *d) { const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left; tdefl_flush flush = d->m_flush; while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) { mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; /* Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. */ if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) { mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; src_buf_left -= num_bytes_to_process; d->m_lookahead_size += num_bytes_to_process; while (pSrc != pSrc_end) { mz_uint8 c = *pSrc++; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++; } } else { while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) { mz_uint8 c = *pSrc++; mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; src_buf_left--; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) { mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); } } } d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) break; /* Simple lazy/greedy parsing state machine. */ len_to_move = 1; cur_match_dist = 0; cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) { if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) { mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; cur_match_len = 0; while (cur_match_len < d->m_lookahead_size) { if (d->m_dict[cur_pos + cur_match_len] != c) break; cur_match_len++; } if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1; } } else { tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); } if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) { cur_match_dist = cur_match_len = 0; } if (d->m_saved_match_len) { if (cur_match_len > d->m_saved_match_len) { tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); if (cur_match_len >= 128) { tdefl_record_match(d, cur_match_len, cur_match_dist); d->m_saved_match_len = 0; len_to_move = cur_match_len; } else { d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; } } else { tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0; } } else if (!cur_match_dist) tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) { tdefl_record_match(d, cur_match_len, cur_match_dist); len_to_move = cur_match_len; } else { d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; } /* Move the lookahead forward by len_to_move bytes. */ d->m_lookahead_pos += len_to_move; MZ_ASSERT(d->m_lookahead_size >= len_to_move); d->m_lookahead_size -= len_to_move; d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE); /* Check if it's time to flush the current LZ codes to the internal output buffer. */ if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || ((d->m_total_lz_bytes > 31 * 1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) { int n; d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; } } d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; return MZ_TRUE; } static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) { if (d->m_pIn_buf_size) { *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; } if (d->m_pOut_buf_size) { size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); d->m_output_flush_ofs += (mz_uint)n; d->m_output_flush_remaining -= (mz_uint)n; d->m_out_buf_ofs += n; *d->m_pOut_buf_size = d->m_out_buf_ofs; } return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; } tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) { if (!d) { if (pIn_buf_size) *pIn_buf_size = 0; if (pOut_buf_size) *pOut_buf_size = 0; return TDEFL_STATUS_BAD_PARAM; } d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size; d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size; d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; d->m_out_buf_ofs = 0; d->m_flush = flush; if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf)) { if (pIn_buf_size) *pIn_buf_size = 0; if (pOut_buf_size) *pOut_buf_size = 0; return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); } d->m_wants_to_finish |= (flush == TDEFL_FINISH); if ((d->m_output_flush_remaining) || (d->m_finished)) return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) { if (!tdefl_compress_fast(d)) return d->m_prev_return_status; } else #endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ { if (!tdefl_compress_normal(d)) return d->m_prev_return_status; } if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) { if (tdefl_flush_block(d, flush) < 0) return d->m_prev_return_status; d->m_finished = (flush == TDEFL_FINISH); if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_OBJ(d->m_hash); MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; } } return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); } tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) { MZ_ASSERT(d->m_pPut_buf_func); return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); } tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) { d->m_pPut_buf_func = pPut_buf_func; d->m_pPut_buf_user = pPut_buf_user; d->m_flags = (mz_uint)(flags); d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash); d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_pOutput_buf = d->m_output_buf; d->m_pOutput_buf_end = d->m_output_buf; d->m_prev_return_status = TDEFL_STATUS_OKAY; d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1; d->m_pIn_buf = NULL; d->m_pOut_buf = NULL; d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL; d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0; if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_dict); memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); return TDEFL_STATUS_OKAY; } tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) { return d->m_prev_return_status; } mz_uint32 tdefl_get_adler32(tdefl_compressor *d) { return d->m_adler32; } mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) { tdefl_compressor *pComp; mz_bool succeeded; if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE; pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); if (!pComp) return MZ_FALSE; succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); MZ_FREE(pComp); return succeeded; } typedef struct { size_t m_size, m_capacity; mz_uint8 *m_pBuf; mz_bool m_expandable; } tdefl_output_buffer; static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) { tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; size_t new_size = p->m_size + len; if (new_size > p->m_capacity) { size_t new_capacity = p->m_capacity; mz_uint8 *pNew_buf; if (!p->m_expandable) return MZ_FALSE; do { new_capacity = MZ_MAX(128U, new_capacity << 1U); } while (new_size > new_capacity); pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); if (!pNew_buf) return MZ_FALSE; p->m_pBuf = pNew_buf; p->m_capacity = new_capacity; } memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); p->m_size = new_size; return MZ_TRUE; } void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) { tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); if (!pOut_len) return MZ_FALSE; else *pOut_len = 0; out_buf.m_expandable = MZ_TRUE; if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return NULL; *pOut_len = out_buf.m_size; return out_buf.m_pBuf; } size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) { tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); if (!pOut_buf) return 0; out_buf.m_pBuf = (mz_uint8 *)pOut_buf; out_buf.m_capacity = out_buf_len; if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return 0; return out_buf.m_size; } static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; /* level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). */ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) { mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES; else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK; else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES; return comp_flags; } #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4204) /* nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) */ #endif /* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. */ void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) { /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, bpl = w * num_chans, y, z; mz_uint32 c; *pLen_out = 0; if (!pComp) return NULL; MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE; out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); return NULL; } /* write dummy header */ for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf); /* compress image data */ tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); for (y = 0; y < h; ++y) { tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); } if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } /* write real header */ *pLen_out = out_buf.m_size - 41; { static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x44, 0x41, 0x54 }; pnghdr[18] = (mz_uint8)(w >> 8); pnghdr[19] = (mz_uint8)w; pnghdr[22] = (mz_uint8)(h >> 8); pnghdr[23] = (mz_uint8)h; pnghdr[25] = chans[num_chans]; pnghdr[33] = (mz_uint8)(*pLen_out >> 24); pnghdr[34] = (mz_uint8)(*pLen_out >> 16); pnghdr[35] = (mz_uint8)(*pLen_out >> 8); pnghdr[36] = (mz_uint8)*pLen_out; c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); for (i = 0; i < 4; ++i, c <<= 8) ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); memcpy(out_buf.m_pBuf, pnghdr, 41); } /* write footer (IDAT CRC-32, followed by IEND chunk) */ if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); for (i = 0; i < 4; ++i, c <<= 8) (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); /* compute final size of file, grab compressed data buffer and return */ *pLen_out += 57; MZ_FREE(pComp); return out_buf.m_pBuf; } void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) { /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) */ return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); } /* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */ /* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */ /* structure size and allocation mechanism. */ tdefl_compressor *tdefl_compressor_alloc() { return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); } void tdefl_compressor_free(tdefl_compressor *pComp) { MZ_FREE(pComp); } #ifdef _MSC_VER #pragma warning(pop) #endif #ifdef __cplusplus } #endif /************************************************************************** * * Copyright 2013-2014 RAD Game Tools and Valve Software * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * **************************************************************************/ #ifdef __cplusplus extern "C" { #endif /* ------------------- Low-level Decompression (completely independent from all compression API's) */ #define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) #define TINFL_MEMSET(p, c, l) memset(p, c, l) #define TINFL_CR_BEGIN \ switch (r->m_state) \ { \ case 0: #define TINFL_CR_RETURN(state_index, result) \ do \ { \ status = result; \ r->m_state = state_index; \ goto common_exit; \ case state_index:; \ } \ MZ_MACRO_END #define TINFL_CR_RETURN_FOREVER(state_index, result) \ do \ { \ for (;;) \ { \ TINFL_CR_RETURN(state_index, result); \ } \ } \ MZ_MACRO_END #define TINFL_CR_FINISH } #define TINFL_GET_BYTE(state_index, c) \ do \ { \ while (pIn_buf_cur >= pIn_buf_end) \ { \ TINFL_CR_RETURN(state_index, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); \ } \ c = *pIn_buf_cur++; \ } \ MZ_MACRO_END #define TINFL_NEED_BITS(state_index, n) \ do \ { \ mz_uint c; \ TINFL_GET_BYTE(state_index, c); \ bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ num_bits += 8; \ } while (num_bits < (mz_uint)(n)) #define TINFL_SKIP_BITS(state_index, n) \ do \ { \ if (num_bits < (mz_uint)(n)) \ { \ TINFL_NEED_BITS(state_index, n); \ } \ bit_buf >>= (n); \ num_bits -= (n); \ } \ MZ_MACRO_END #define TINFL_GET_BITS(state_index, b, n) \ do \ { \ if (num_bits < (mz_uint)(n)) \ { \ TINFL_NEED_BITS(state_index, n); \ } \ b = bit_buf & ((1 << (n)) - 1); \ bit_buf >>= (n); \ num_bits -= (n); \ } \ MZ_MACRO_END /* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. */ /* It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a */ /* Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the */ /* bit buffer contains >=15 bits (deflate's max. Huffman code size). */ #define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ do \ { \ temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ if (temp >= 0) \ { \ code_len = temp >> 9; \ if ((code_len) && (num_bits >= code_len)) \ break; \ } \ else if (num_bits > TINFL_FAST_LOOKUP_BITS) \ { \ code_len = TINFL_FAST_LOOKUP_BITS; \ do \ { \ temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ } while ((temp < 0) && (num_bits >= (code_len + 1))); \ if (temp >= 0) \ break; \ } \ TINFL_GET_BYTE(state_index, c); \ bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ num_bits += 8; \ } while (num_bits < 15); /* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read */ /* beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully */ /* decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. */ /* The slow path is only executed at the very end of the input buffer. */ /* v1.16: The original macro handled the case at the very end of the passed-in input buffer, but we also need to handle the case where the user passes in 1+zillion bytes */ /* following the deflate data and our non-conservative read-ahead path won't kick in here on this code. This is much trickier. */ #define TINFL_HUFF_DECODE(state_index, sym, pHuff) \ do \ { \ int temp; \ mz_uint code_len, c; \ if (num_bits < 15) \ { \ if ((pIn_buf_end - pIn_buf_cur) < 2) \ { \ TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ } \ else \ { \ bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \ pIn_buf_cur += 2; \ num_bits += 16; \ } \ } \ if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ code_len = temp >> 9, temp &= 511; \ else \ { \ code_len = TINFL_FAST_LOOKUP_BITS; \ do \ { \ temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ } while (temp < 0); \ } \ sym = temp; \ bit_buf >>= code_len; \ num_bits -= code_len; \ } \ MZ_MACRO_END tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) { static const int s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; static const int s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; static const int s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 }; static const int s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; static const mz_uint8 s_length_dezigzag[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; static const int s_min_table_sizes[3] = { 257, 1, 4 }; tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; /* Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). */ if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; } num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; TINFL_CR_BEGIN bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1); counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } } do { TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; if (r->m_type == 0) { TINFL_SKIP_BITS(5, num_bits & 7); for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); } if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } while ((counter) && (num_bits)) { TINFL_GET_BITS(51, dist, 8); while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } *pOut_buf_cur++ = (mz_uint8)dist; counter--; } while (counter) { size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } while (pIn_buf_cur >= pIn_buf_end) { TINFL_CR_RETURN(38, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); } n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n; } } else if (r->m_type == 3) { TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); } else { if (r->m_type == 1) { mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i; r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); for (i = 0; i <= 143; ++i) *p++ = 8; for (; i <= 255; ++i) *p++ = 9; for (; i <= 279; ++i) *p++ = 7; for (; i <= 287; ++i) *p++ = 8; } else { for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } r->m_table_sizes[2] = 19; } for (; (int)r->m_type >= 0; r->m_type--) { int tree_next, tree_cur; tinfl_huff_table *pTable; mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree); for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } if ((65536 != total) && (used_syms > 1)) { TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); } for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) { mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) { tree_cur -= ((rev_code >>= 1) & 1); if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1]; } tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; } if (r->m_type == 2) { for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) { mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; } if ((dist == 16) && (!counter)) { TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); } num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; } if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) { TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); } TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); } } for (;;) { mz_uint8 *pSrc; for (;;) { if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) { TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); if (counter >= 256) break; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } *pOut_buf_cur++ = (mz_uint8)counter; } else { int sym2; mz_uint code_len; #if TINFL_USE_64BIT_BITBUF if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } #else if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } #endif if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) code_len = sym2 >> 9; else { code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); } counter = sym2; bit_buf >>= code_len; num_bits -= code_len; if (counter & 256) break; #if !TINFL_USE_64BIT_BITBUF if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } #endif if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) code_len = sym2 >> 9; else { code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); } bit_buf >>= code_len; num_bits -= code_len; pOut_buf_cur[0] = (mz_uint8)counter; if (sym2 & 256) { pOut_buf_cur++; counter = sym2; break; } pOut_buf_cur[1] = (mz_uint8)sym2; pOut_buf_cur += 2; } } if ((counter &= 511) == 256) break; num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) { TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); } pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) { while (counter--) { while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; } continue; } #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES else if ((counter >= 9) && (counter <= dist)) { const mz_uint8 *pSrc_end = pSrc + (counter & ~7); do { ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; pOut_buf_cur += 8; } while ((pSrc += 8) < pSrc_end); if ((counter &= 7) < 3) { if (counter) { pOut_buf_cur[0] = pSrc[0]; if (counter > 1) pOut_buf_cur[1] = pSrc[1]; pOut_buf_cur += counter; } continue; } } #endif do { pOut_buf_cur[0] = pSrc[0]; pOut_buf_cur[1] = pSrc[1]; pOut_buf_cur[2] = pSrc[2]; pOut_buf_cur += 3; pSrc += 3; } while ((int)(counter -= 3) > 2); if ((int)counter > 0) { pOut_buf_cur[0] = pSrc[0]; if ((int)counter > 1) pOut_buf_cur[1] = pSrc[1]; pOut_buf_cur += counter; } } } } while (!(r->m_final & 1)); /* Ensure byte alignment and put back any bytes from the bitbuf if we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ /* I'm being super conservative here. A number of simplifications can be made to the byte alignment part, and the Adler32 check shouldn't ever need to worry about reading from the bitbuf now. */ TINFL_SKIP_BITS(32, num_bits & 7); while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) { --pIn_buf_cur; num_bits -= 8; } bit_buf &= (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); MZ_ASSERT(!num_bits); /* if this assert fires then we've read beyond the end of non-deflate/zlib streams with following data (such as gzip streams). */ if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } } TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); TINFL_CR_FINISH common_exit: /* As long as we aren't telling the caller that we NEED more input to make forward progress: */ /* Put back any bytes from the bitbuf in case we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ /* We need to be very careful here to NOT push back any bytes we definitely know we need to make forward progress, though, or we'll lock the caller up into an inf loop. */ if ((status != TINFL_STATUS_NEEDS_MORE_INPUT) && (status != TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS)) { while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) { --pIn_buf_cur; num_bits -= 8; } } r->m_num_bits = num_bits; r->m_bit_buf = bit_buf & (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) { const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; while (buf_len) { for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; } for (; i < block_len; ++i) s1 += *ptr++, s2 += s1; s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; } r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; } return status; } /* Higher level helper functions. */ void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) { tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0; *pOut_len = 0; tinfl_init(&decomp); for (;;) { size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) { MZ_FREE(pBuf); *pOut_len = 0; return NULL; } src_buf_ofs += src_buf_size; *pOut_len += dst_buf_size; if (status == TINFL_STATUS_DONE) break; new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); if (!pNew_buf) { MZ_FREE(pBuf); *pOut_len = 0; return NULL; } pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity; } return pBuf; } size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) { tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp); status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; } int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) { int result = 0; tinfl_decompressor decomp; mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0; if (!pDict) return TINFL_STATUS_FAILED; tinfl_init(&decomp); for (;;) { size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); in_buf_ofs += in_buf_size; if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) break; if (status != TINFL_STATUS_HAS_MORE_OUTPUT) { result = (status == TINFL_STATUS_DONE); break; } dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); } MZ_FREE(pDict); *pIn_buf_size = in_buf_ofs; return result; } tinfl_decompressor *tinfl_decompressor_alloc() { tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); if (pDecomp) tinfl_init(pDecomp); return pDecomp; } void tinfl_decompressor_free(tinfl_decompressor *pDecomp) { MZ_FREE(pDecomp); } #ifdef __cplusplus } #endif /************************************************************************** * * Copyright 2013-2014 RAD Game Tools and Valve Software * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC * Copyright 2016 Martin Raiber * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * **************************************************************************/ #ifndef MINIZ_NO_ARCHIVE_APIS #ifdef __cplusplus extern "C" { #endif /* ------------------- .ZIP archive reading */ #ifdef MINIZ_NO_STDIO #define MZ_FILE void * #else #include #if defined(_MSC_VER) || defined(__MINGW64__) static FILE *mz_fopen(const char *pFilename, const char *pMode) { FILE *pFile = NULL; fopen_s(&pFile, pFilename, pMode); return pFile; } static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) { FILE *pFile = NULL; if (freopen_s(&pFile, pPath, pMode, pStream)) return NULL; return pFile; } #ifndef MINIZ_NO_TIME #include #endif #define MZ_FOPEN mz_fopen #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 _ftelli64 #define MZ_FSEEK64 _fseeki64 #define MZ_FILE_STAT_STRUCT _stat #define MZ_FILE_STAT _stat #define MZ_FFLUSH fflush #define MZ_FREOPEN mz_freopen #define MZ_DELETE_FILE remove #elif defined(__MINGW32__) #ifndef MINIZ_NO_TIME #include #endif #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 ftello64 #define MZ_FSEEK64 fseeko64 #define MZ_FILE_STAT_STRUCT _stat #define MZ_FILE_STAT _stat #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove #elif defined(__TINYC__) #ifndef MINIZ_NO_TIME #include #endif #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 ftell #define MZ_FSEEK64 fseek #define MZ_FILE_STAT_STRUCT stat #define MZ_FILE_STAT stat #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove #elif defined(__GNUC__) && _LARGEFILE64_SOURCE #ifndef MINIZ_NO_TIME #include #endif #define MZ_FOPEN(f, m) fopen64(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 ftello64 #define MZ_FSEEK64 fseeko64 #define MZ_FILE_STAT_STRUCT stat64 #define MZ_FILE_STAT stat64 #define MZ_FFLUSH fflush #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) #define MZ_DELETE_FILE remove #elif defined(__APPLE__) #ifndef MINIZ_NO_TIME #include #endif #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 ftello #define MZ_FSEEK64 fseeko #define MZ_FILE_STAT_STRUCT stat #define MZ_FILE_STAT stat #define MZ_FFLUSH fflush #define MZ_FREOPEN(p, m, s) freopen(p, m, s) #define MZ_DELETE_FILE remove #else #pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") #ifndef MINIZ_NO_TIME #include #endif #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #ifdef __STRICT_ANSI__ #define MZ_FTELL64 ftell #define MZ_FSEEK64 fseek #else #define MZ_FTELL64 ftello #define MZ_FSEEK64 fseeko #endif #define MZ_FILE_STAT_STRUCT stat #define MZ_FILE_STAT stat #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove #endif /* #ifdef _MSC_VER */ #endif /* #ifdef MINIZ_NO_STDIO */ #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) /* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */ enum { /* ZIP archive identifiers and record sizes */ MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, /* ZIP64 archive identifier and record sizes */ MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, /* Central directory header record offsets */ MZ_ZIP_CDH_SIG_OFS = 0, MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, MZ_ZIP_CDH_BIT_FLAG_OFS = 8, MZ_ZIP_CDH_METHOD_OFS = 10, MZ_ZIP_CDH_FILE_TIME_OFS = 12, MZ_ZIP_CDH_FILE_DATE_OFS = 14, MZ_ZIP_CDH_CRC32_OFS = 16, MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, MZ_ZIP_CDH_DISK_START_OFS = 34, MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, /* Local directory header offsets */ MZ_ZIP_LDH_SIG_OFS = 0, MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, MZ_ZIP_LDH_BIT_FLAG_OFS = 6, MZ_ZIP_LDH_METHOD_OFS = 8, MZ_ZIP_LDH_FILE_TIME_OFS = 10, MZ_ZIP_LDH_FILE_DATE_OFS = 12, MZ_ZIP_LDH_CRC32_OFS = 14, MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, /* End of central directory offsets */ MZ_ZIP_ECDH_SIG_OFS = 0, MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, /* ZIP64 End of central directory locator offsets */ MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ /* ZIP64 End of central directory header offsets */ MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 }; typedef struct { void *m_p; size_t m_size, m_capacity; mz_uint m_element_size; } mz_zip_array; struct mz_zip_internal_state_tag { mz_zip_array m_central_dir; mz_zip_array m_central_dir_offsets; mz_zip_array m_sorted_central_dir_offsets; /* The flags passed in when the archive is initially opened. */ uint32_t m_init_flags; /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ mz_bool m_zip64; /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */ mz_bool m_zip64_has_extended_info_fields; /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */ MZ_FILE *m_pFile; mz_uint64 m_file_archive_start_ofs; void *m_pMem; size_t m_mem_size; size_t m_mem_capacity; }; #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size #if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG) static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) { MZ_ASSERT(index < pArray->m_size); return index; } #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)] #else #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] #endif static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) { memset(pArray, 0, sizeof(mz_zip_array)); pArray->m_element_size = element_size; } static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) { pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); memset(pArray, 0, sizeof(mz_zip_array)); } static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) { void *pNew_p; size_t new_capacity = min_new_capacity; MZ_ASSERT(pArray->m_element_size); if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE; if (growing) { new_capacity = MZ_MAX(1, pArray->m_capacity); while (new_capacity < min_new_capacity) new_capacity *= 2; } if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) return MZ_FALSE; pArray->m_p = pNew_p; pArray->m_capacity = new_capacity; return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) { if (new_capacity > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) return MZ_FALSE; } return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) { if (new_size > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return MZ_FALSE; } pArray->m_size = new_size; return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) { return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); } static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) { size_t orig_size = pArray->m_size; if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) return MZ_FALSE; memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); return MZ_TRUE; } #ifndef MINIZ_NO_TIME static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) { struct tm tm; memset(&tm, 0, sizeof(tm)); tm.tm_isdst = -1; tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; tm.tm_mon = ((dos_date >> 5) & 15) - 1; tm.tm_mday = dos_date & 31; tm.tm_hour = (dos_time >> 11) & 31; tm.tm_min = (dos_time >> 5) & 63; tm.tm_sec = (dos_time << 1) & 62; return mktime(&tm); } #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) { #ifdef _MSC_VER struct tm tm_struct; struct tm *tm = &tm_struct; errno_t err = localtime_s(tm, &time); if (err) { *pDOS_date = 0; *pDOS_time = 0; return; } #else struct tm *tm = localtime(&time); #endif /* #ifdef _MSC_VER */ *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); } #endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ #ifndef MINIZ_NO_STDIO #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) { struct MZ_FILE_STAT_STRUCT file_stat; /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ if (MZ_FILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE; *pTime = file_stat.st_mtime; return MZ_TRUE; } #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) { struct utimbuf t; memset(&t, 0, sizeof(t)); t.actime = access_time; t.modtime = modified_time; return !utime(pFilename, &t); } #endif /* #ifndef MINIZ_NO_STDIO */ #endif /* #ifndef MINIZ_NO_TIME */ static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) { if (pZip) pZip->m_last_error = err_num; return MZ_FALSE; } static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) { (void)flags; if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!pZip->m_pAlloc) pZip->m_pAlloc = miniz_def_alloc_func; if (!pZip->m_pFree) pZip->m_pFree = miniz_def_free_func; if (!pZip->m_pRealloc) pZip->m_pRealloc = miniz_def_realloc_func; pZip->m_archive_size = 0; pZip->m_central_directory_file_ofs = 0; pZip->m_total_files = 0; pZip->m_last_error = MZ_ZIP_NO_ERROR; if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); pZip->m_pState->m_init_flags = flags; pZip->m_pState->m_zip64 = MZ_FALSE; pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; pZip->m_zip_mode = MZ_ZIP_MODE_READING; return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) { const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); mz_uint8 l = 0, r = 0; pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pE = pL + MZ_MIN(l_len, r_len); while (pL < pE) { if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; pL++; pR++; } return (pL == pE) ? (l_len < r_len) : (l < r); } #define MZ_SWAP_UINT32(a, b) \ do \ { \ mz_uint32 t = a; \ a = b; \ b = t; \ } \ MZ_MACRO_END /* Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) */ static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) { mz_zip_internal_state *pState = pZip->m_pState; const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; const mz_zip_array *pCentral_dir = &pState->m_central_dir; mz_uint32 *pIndices; mz_uint32 start, end; const mz_uint32 size = pZip->m_total_files; if (size <= 1U) return; pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); start = (size - 2U) >> 1U; for (;;) { mz_uint64 child, root = start; for (;;) { if ((child = (root << 1U) + 1U) >= size) break; child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) break; MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; } if (!start) break; start--; } end = size - 1; while (end > 0) { mz_uint64 child, root = 0; MZ_SWAP_UINT32(pIndices[end], pIndices[0]); for (;;) { if ((child = (root << 1U) + 1U) >= end) break; child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) break; MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; } end--; } } static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) { mz_int64 cur_file_ofs; mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32; /* Basic sanity checks - reject files which are too small */ if (pZip->m_archive_size < record_size) return MZ_FALSE; /* Find the record by scanning the file from the end towards the beginning. */ cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); for (;;) { int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) return MZ_FALSE; for (i = n - 4; i >= 0; --i) { mz_uint s = MZ_READ_LE32(pBuf + i); if (s == record_sig) { if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) break; } } if (i >= 0) { cur_file_ofs += i; break; } /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) return MZ_FALSE; cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); } *pOfs = cur_file_ofs; return MZ_TRUE; } static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) { mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; mz_uint64 cdir_ofs = 0; mz_int64 cur_file_ofs = 0; const mz_uint8 *p; mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32; mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; mz_uint64 zip64_end_of_central_dir_ofs = 0; /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */ if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); /* Read and verify the end of central directory record. */ if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) { if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) { if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) { zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) { if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) { pZip->m_pState->m_zip64 = MZ_TRUE; } } } } } pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); if (pZip->m_pState->m_zip64) { mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if (zip64_total_num_of_disks != 1U) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); /* Check for miniz's practical limits */ if (zip64_cdir_total_entries > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */ if (zip64_size_of_central_directory > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); cdir_size = (mz_uint32)zip64_size_of_central_directory; num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); } if (pZip->m_total_files != cdir_entries_on_this_disk) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); pZip->m_central_directory_file_ofs = cdir_ofs; if (pZip->m_total_files) { mz_uint i, n; /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */ if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); if (sort_central_dir) { if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); /* Now create an index into the central directory file records, do some basic sanity checking on each record */ p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) { mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; mz_uint64 comp_size, decomp_size, local_header_ofs; if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); if (sort_central_dir) MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && (ext_data_size) && (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) { /* Attempt to find zip64 extended information field in the entry's extra data */ mz_uint32 extra_size_remaining = ext_data_size; if (extra_size_remaining) { const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; do { mz_uint32 field_id; mz_uint32 field_data_size; if (extra_size_remaining < (sizeof(mz_uint16) * 2)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); field_id = MZ_READ_LE16(pExtra_data); field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) { /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */ pZip->m_pState->m_zip64 = MZ_TRUE; pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; break; } pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; } while (extra_size_remaining); } } /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */ if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) { if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); } disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); if (comp_size != MZ_UINT32_MAX) { if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); } bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); n -= total_header_size; p += total_header_size; } } if (sort_central_dir) mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); return MZ_TRUE; } void mz_zip_zero_struct(mz_zip_archive *pZip) { if (pZip) MZ_CLEAR_OBJ(*pZip); } static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) { mz_bool status = MZ_TRUE; if (!pZip) return MZ_FALSE; if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) { if (set_last_error) pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; return MZ_FALSE; } if (pZip->m_pState) { mz_zip_internal_state *pState = pZip->m_pState; pZip->m_pState = NULL; mz_zip_array_clear(pZip, &pState->m_central_dir); mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); #ifndef MINIZ_NO_STDIO if (pState->m_pFile) { if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) { if (MZ_FCLOSE(pState->m_pFile) == EOF) { if (set_last_error) pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; status = MZ_FALSE; } } pState->m_pFile = NULL; } #endif /* #ifndef MINIZ_NO_STDIO */ pZip->m_pFree(pZip->m_pAlloc_opaque, pState); } pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; return status; } mz_bool mz_zip_reader_end(mz_zip_archive *pZip) { return mz_zip_reader_end_internal(pZip, MZ_TRUE); } mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) { if ((!pZip) || (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; pZip->m_zip_type = MZ_ZIP_TYPE_USER; pZip->m_archive_size = size; if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end_internal(pZip, MZ_FALSE); return MZ_FALSE; } return MZ_TRUE; } static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); return s; } mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) { if (!pMem) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; pZip->m_archive_size = size; pZip->m_pRead = mz_zip_mem_read_func; pZip->m_pIO_opaque = pZip; pZip->m_pNeeds_keepalive = NULL; #ifdef __cplusplus pZip->m_pState->m_pMem = const_cast(pMem); #else pZip->m_pState->m_pMem = (void *)pMem; #endif pZip->m_pState->m_mem_size = size; if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end_internal(pZip, MZ_FALSE); return MZ_FALSE; } return MZ_TRUE; } #ifndef MINIZ_NO_STDIO static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); file_ofs += pZip->m_pState->m_file_archive_start_ofs; if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) return 0; return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); } mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) { return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); } mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) { mz_uint64 file_size; MZ_FILE *pFile; if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pFile = MZ_FOPEN(pFilename, "rb"); if (!pFile) return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); file_size = archive_size; if (!file_size) { if (MZ_FSEEK64(pFile, 0, SEEK_END)) { MZ_FCLOSE(pFile); return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); } file_size = MZ_FTELL64(pFile); } /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) { MZ_FCLOSE(pFile); return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); } if (!mz_zip_reader_init_internal(pZip, flags)) { MZ_FCLOSE(pFile); return MZ_FALSE; } pZip->m_zip_type = MZ_ZIP_TYPE_FILE; pZip->m_pRead = mz_zip_file_read_func; pZip->m_pIO_opaque = pZip; pZip->m_pState->m_pFile = pFile; pZip->m_archive_size = file_size; pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end_internal(pZip, MZ_FALSE); return MZ_FALSE; } return MZ_TRUE; } mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) { mz_uint64 cur_file_ofs; if ((!pZip) || (!pFile)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); cur_file_ofs = MZ_FTELL64(pFile); if (!archive_size) { if (MZ_FSEEK64(pFile, 0, SEEK_END)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); archive_size = MZ_FTELL64(pFile) - cur_file_ofs; if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); } if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; pZip->m_pRead = mz_zip_file_read_func; pZip->m_pIO_opaque = pZip; pZip->m_pState->m_pFile = pFile; pZip->m_archive_size = archive_size; pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end_internal(pZip, MZ_FALSE); return MZ_FALSE; } return MZ_TRUE; } #endif /* #ifndef MINIZ_NO_STDIO */ static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) { if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) return NULL; return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); } mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) { mz_uint m_bit_flag; const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); if (!p) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return MZ_FALSE; } m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; } mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) { mz_uint bit_flag; mz_uint method; const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); if (!p) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return MZ_FALSE; } method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); if ((method != 0) && (method != MZ_DEFLATED)) { mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); return MZ_FALSE; } if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) { mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); return MZ_FALSE; } if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) { mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); return MZ_FALSE; } return MZ_TRUE; } mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) { mz_uint filename_len, attribute_mapping_id, external_attr; const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); if (!p) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return MZ_FALSE; } filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); if (filename_len) { if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') return MZ_TRUE; } /* Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. */ /* Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. */ /* FIXME: Remove this check? Is it necessary - we already check the filename. */ attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; (void)attribute_mapping_id; external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) { return MZ_TRUE; } return MZ_FALSE; } static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) { mz_uint n; const mz_uint8 *p = pCentral_dir_header; if (pFound_zip64_extra_data) *pFound_zip64_extra_data = MZ_FALSE; if ((!p) || (!pStat)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); /* Extract fields from the central directory record. */ pStat->m_file_index = file_index; pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); #ifndef MINIZ_NO_TIME pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); #endif pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); /* Copy as much of the filename and comment as possible. */ n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pStat->m_filename[n] = '\0'; n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); pStat->m_comment_size = n; memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); pStat->m_comment[n] = '\0'; /* Set some flags for convienance */ pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); /* See if we need to read any zip64 extended information fields. */ /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */ if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) { /* Attempt to find zip64 extended information field in the entry's extra data */ mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); if (extra_size_remaining) { const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); do { mz_uint32 field_id; mz_uint32 field_data_size; if (extra_size_remaining < (sizeof(mz_uint16) * 2)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); field_id = MZ_READ_LE16(pExtra_data); field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) { const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; mz_uint32 field_data_remaining = field_data_size; if (pFound_zip64_extra_data) *pFound_zip64_extra_data = MZ_TRUE; if (pStat->m_uncomp_size == MZ_UINT32_MAX) { if (field_data_remaining < sizeof(mz_uint64)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); pStat->m_uncomp_size = MZ_READ_LE64(pField_data); pField_data += sizeof(mz_uint64); field_data_remaining -= sizeof(mz_uint64); } if (pStat->m_comp_size == MZ_UINT32_MAX) { if (field_data_remaining < sizeof(mz_uint64)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); pStat->m_comp_size = MZ_READ_LE64(pField_data); pField_data += sizeof(mz_uint64); field_data_remaining -= sizeof(mz_uint64); } if (pStat->m_local_header_ofs == MZ_UINT32_MAX) { if (field_data_remaining < sizeof(mz_uint64)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); pField_data += sizeof(mz_uint64); field_data_remaining -= sizeof(mz_uint64); } break; } pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; } while (extra_size_remaining); } } return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) { mz_uint i; if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) return 0 == memcmp(pA, pB, len); for (i = 0; i < len; ++i) if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) return MZ_FALSE; return MZ_TRUE; } static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) { const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); mz_uint8 l = 0, r = 0; pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pE = pL + MZ_MIN(l_len, r_len); while (pL < pE) { if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; pL++; pR++; } return (pL == pE) ? (int)(l_len - r_len) : (l - r); } static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) { mz_zip_internal_state *pState = pZip->m_pState; const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; const mz_zip_array *pCentral_dir = &pState->m_central_dir; mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); const uint32_t size = pZip->m_total_files; const mz_uint filename_len = (mz_uint)strlen(pFilename); if (pIndex) *pIndex = 0; if (size) { /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */ /* honestly the major expense here on 32-bit CPU's will still be the filename compare */ mz_int64 l = 0, h = (mz_int64)size - 1; while (l <= h) { mz_int64 m = l + ((h - l) >> 1); uint32_t file_index = pIndices[(uint32_t)m]; int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); if (!comp) { if (pIndex) *pIndex = file_index; return MZ_TRUE; } else if (comp < 0) l = m + 1; else h = m - 1; } } return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); } int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) { mz_uint32 index; if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index)) return -1; else return (int)index; } mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) { mz_uint file_index; size_t name_len, comment_len; if (pIndex) *pIndex = 0; if ((!pZip) || (!pZip->m_pState) || (!pName)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); /* See if we can use a binary search */ if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) { return mz_zip_locate_file_binary_search(pZip, pName, pIndex); } /* Locate the entry by scanning the entire central directory */ name_len = strlen(pName); if (name_len > MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); comment_len = pComment ? strlen(pComment) : 0; if (comment_len > MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); for (file_index = 0; file_index < pZip->m_total_files; file_index++) { const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; if (filename_len < name_len) continue; if (comment_len) { mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); const char *pFile_comment = pFilename + filename_len + file_extra_len; if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) continue; } if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) { int ofs = filename_len - 1; do { if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) break; } while (--ofs >= 0); ofs++; pFilename += ofs; filename_len -= ofs; } if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) { if (pIndex) *pIndex = file_index; return MZ_TRUE; } } return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); } mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) { int status = TINFL_STATUS_DONE; mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; mz_zip_archive_file_stat file_stat; void *pRead_buf; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; tinfl_decompressor inflator; if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; /* A directory or zero length file */ if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) return MZ_TRUE; /* Encryption and patch files are not supported. */ if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); /* This function only supports decompressing stored and deflate. */ if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); /* Ensure supplied output buffer is large enough. */ needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; if (buf_size < needed_size) return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); /* Read and parse the local directory entry. */ cur_file_ofs = file_stat.m_local_header_ofs; if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { /* The file is stored or the caller has requested the compressed data. */ if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) { if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); } #endif return MZ_TRUE; } /* Decompress the file either directly from memory or from a file input buffer. */ tinfl_init(&inflator); if (pZip->m_pState->m_pMem) { /* Read directly from the archive in memory. */ pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; read_buf_size = read_buf_avail = file_stat.m_comp_size; comp_remaining = 0; } else if (pUser_read_buf) { /* Use a user provided read buffer. */ if (!user_read_buf_size) return MZ_FALSE; pRead_buf = (mz_uint8 *)pUser_read_buf; read_buf_size = user_read_buf_size; read_buf_avail = 0; comp_remaining = file_stat.m_comp_size; } else { /* Temporarily allocate a read buffer. */ read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); read_buf_avail = 0; comp_remaining = file_stat.m_comp_size; } do { /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */ size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { status = TINFL_STATUS_FAILED; mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); break; } cur_file_ofs += read_buf_avail; comp_remaining -= read_buf_avail; read_buf_ofs = 0; } in_buf_size = (size_t)read_buf_avail; status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); read_buf_avail -= in_buf_size; read_buf_ofs += in_buf_size; out_buf_ofs += out_buf_size; } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); if (status == TINFL_STATUS_DONE) { /* Make sure the entire file was decompressed, and check its CRC. */ if (out_buf_ofs != file_stat.m_uncomp_size) { mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); status = TINFL_STATUS_FAILED; } #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) { mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); status = TINFL_STATUS_FAILED; } #endif } if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); return status == TINFL_STATUS_DONE; } mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) { mz_uint32 file_index; if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) return MZ_FALSE; return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); } mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) { return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); } mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) { return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); } void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) { mz_uint64 comp_size, uncomp_size, alloc_size; const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); void *pBuf; if (pSize) *pSize = 0; if (!p) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return NULL; } comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) { mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); return NULL; } if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); return NULL; } if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return NULL; } if (pSize) *pSize = (size_t)alloc_size; return pBuf; } void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) { mz_uint32 file_index; if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) { if (pSize) *pSize = 0; return MZ_FALSE; } return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); } mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) { int status = TINFL_STATUS_DONE; mz_uint file_crc32 = MZ_CRC32_INIT; mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; mz_zip_archive_file_stat file_stat; void *pRead_buf = NULL; void *pWrite_buf = NULL; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; /* A directory or zero length file */ if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) return MZ_TRUE; /* Encryption and patch files are not supported. */ if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); /* This function only supports decompressing stored and deflate. */ if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */ cur_file_ofs = file_stat.m_local_header_ofs; if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); /* Decompress the file either directly from memory or from a file input buffer. */ if (pZip->m_pState->m_pMem) { pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; read_buf_size = read_buf_avail = file_stat.m_comp_size; comp_remaining = 0; } else { read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); read_buf_avail = 0; comp_remaining = file_stat.m_comp_size; } if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { /* The file is stored or the caller has requested the compressed data. */ if (pZip->m_pState->m_pMem) { if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) { mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); status = TINFL_STATUS_FAILED; } else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); #endif } cur_file_ofs += file_stat.m_comp_size; out_buf_ofs += file_stat.m_comp_size; comp_remaining = 0; } else { while (comp_remaining) { read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); status = TINFL_STATUS_FAILED; break; } #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); } #endif if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); status = TINFL_STATUS_FAILED; break; } cur_file_ofs += read_buf_avail; out_buf_ofs += read_buf_avail; comp_remaining -= read_buf_avail; } } } else { tinfl_decompressor inflator; tinfl_init(&inflator); if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); status = TINFL_STATUS_FAILED; } else { do { mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); status = TINFL_STATUS_FAILED; break; } cur_file_ofs += read_buf_avail; comp_remaining -= read_buf_avail; read_buf_ofs = 0; } in_buf_size = (size_t)read_buf_avail; status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); read_buf_avail -= in_buf_size; read_buf_ofs += in_buf_size; if (out_buf_size) { if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) { mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); status = TINFL_STATUS_FAILED; break; } #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); #endif if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) { mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); status = TINFL_STATUS_FAILED; break; } } } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); } } if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) { /* Make sure the entire file was decompressed, and check its CRC. */ if (out_buf_ofs != file_stat.m_uncomp_size) { mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); status = TINFL_STATUS_FAILED; } #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS else if (file_crc32 != file_stat.m_crc32) { mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); status = TINFL_STATUS_FAILED; } #endif } if (!pZip->m_pState->m_pMem) pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); if (pWrite_buf) pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); return status == TINFL_STATUS_DONE; } mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) { mz_uint32 file_index; if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) return MZ_FALSE; return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); } mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) { mz_zip_reader_extract_iter_state *pState; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; /* Argument sanity check */ if ((!pZip) || (!pZip->m_pState)) return NULL; /* Allocate an iterator status structure */ pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); if (!pState) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); return NULL; } /* Fetch file details */ if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } /* Encryption and patch files are not supported. */ if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) { mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } /* This function only supports decompressing stored and deflate. */ if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) { mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } /* Init state - save args */ pState->pZip = pZip; pState->flags = flags; /* Init state - reset variables to defaults */ pState->status = TINFL_STATUS_DONE; #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS pState->file_crc32 = MZ_CRC32_INIT; #endif pState->read_buf_ofs = 0; pState->out_buf_ofs = 0; pState->pRead_buf = NULL; pState->pWrite_buf = NULL; pState->out_blk_remain = 0; /* Read and parse the local directory entry. */ pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } /* Decompress the file either directly from memory or from a file input buffer. */ if (pZip->m_pState->m_pMem) { pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; pState->comp_remaining = pState->file_stat.m_comp_size; } else { if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) { /* Decompression required, therefore intermediate read buffer required */ pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } } else { /* Decompression not required - we will be reading directly into user buffer, no temp buf required */ pState->read_buf_size = 0; } pState->read_buf_avail = 0; pState->comp_remaining = pState->file_stat.m_comp_size; } if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) { /* Decompression required, init decompressor */ tinfl_init( &pState->inflator ); /* Allocate write buffer */ if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); if (pState->pRead_buf) pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } } return pState; } mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) { mz_uint32 file_index; /* Locate file index by name */ if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) return NULL; /* Construct iterator */ return mz_zip_reader_extract_iter_new(pZip, file_index, flags); } size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size) { size_t copied_to_caller = 0; /* Argument sanity check */ if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) return 0; if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) { /* The file is stored or the caller has requested the compressed data, calc amount to return. */ copied_to_caller = MZ_MIN( buf_size, pState->comp_remaining ); /* Zip is in memory....or requires reading from a file? */ if (pState->pZip->m_pState->m_pMem) { /* Copy data to caller's buffer */ memcpy( pvBuf, pState->pRead_buf, copied_to_caller ); pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller; } else { /* Read directly into caller's buffer */ if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) { /* Failed to read all that was asked for, flag failure and alert user */ mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); pState->status = TINFL_STATUS_FAILED; copied_to_caller = 0; } } #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS /* Compute CRC if not returning compressed data only */ if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); #endif /* Advance offsets, dec counters */ pState->cur_file_ofs += copied_to_caller; pState->out_buf_ofs += copied_to_caller; pState->comp_remaining -= copied_to_caller; } else { do { /* Calc ptr to write buffer - given current output pos and block size */ mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); /* Calc max output size - given current output pos and block size */ size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); if (!pState->out_blk_remain) { /* Read more data from file if none available (and reading from file) */ if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) { /* Calc read size */ pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) { mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); pState->status = TINFL_STATUS_FAILED; break; } /* Advance offsets, dec counters */ pState->cur_file_ofs += pState->read_buf_avail; pState->comp_remaining -= pState->read_buf_avail; pState->read_buf_ofs = 0; } /* Perform decompression */ in_buf_size = (size_t)pState->read_buf_avail; pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); pState->read_buf_avail -= in_buf_size; pState->read_buf_ofs += in_buf_size; /* Update current output block size remaining */ pState->out_blk_remain = out_buf_size; } if (pState->out_blk_remain) { /* Calc amount to return. */ size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain ); /* Copy data to caller's buffer */ memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy ); #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS /* Perform CRC */ pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); #endif /* Decrement data consumed from block */ pState->out_blk_remain -= to_copy; /* Inc output offset, while performing sanity check */ if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) { mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); pState->status = TINFL_STATUS_FAILED; break; } /* Increment counter of data copied to caller */ copied_to_caller += to_copy; } } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) ); } /* Return how many bytes were copied into user buffer */ return copied_to_caller; } mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState) { int status; /* Argument sanity check */ if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) return MZ_FALSE; /* Was decompression completed and requested? */ if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) { /* Make sure the entire file was decompressed, and check its CRC. */ if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) { mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); pState->status = TINFL_STATUS_FAILED; } #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS else if (pState->file_crc32 != pState->file_stat.m_crc32) { mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); pState->status = TINFL_STATUS_FAILED; } #endif } /* Free buffers */ if (!pState->pZip->m_pState->m_pMem) pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); if (pState->pWrite_buf) pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); /* Save status */ status = pState->status; /* Free context */ pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); return status == TINFL_STATUS_DONE; } #ifndef MINIZ_NO_STDIO static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) { (void)ofs; return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); } mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) { mz_bool status; mz_zip_archive_file_stat file_stat; MZ_FILE *pFile; if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); pFile = MZ_FOPEN(pDst_filename, "wb"); if (!pFile) return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); if (MZ_FCLOSE(pFile) == EOF) { if (status) mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); status = MZ_FALSE; } #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) if (status) mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); #endif return status; } mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) { mz_uint32 file_index; if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) return MZ_FALSE; return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); } mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) { mz_zip_archive_file_stat file_stat; if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); } mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) { mz_uint32 file_index; if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) return MZ_FALSE; return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); } #endif /* #ifndef MINIZ_NO_STDIO */ static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) { mz_uint32 *p = (mz_uint32 *)pOpaque; (void)file_ofs; *p = (mz_uint32)mz_crc32(*p, (const mz_uint8 *)pBuf, n); return n; } mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) { mz_zip_archive_file_stat file_stat; mz_zip_internal_state *pState; const mz_uint8 *pCentral_dir_header; mz_bool found_zip64_ext_data_in_cdir = MZ_FALSE; mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; mz_uint64 local_header_ofs = 0; mz_uint32 local_header_filename_len, local_header_extra_len, local_header_crc32; mz_uint64 local_header_comp_size, local_header_uncomp_size; mz_uint32 uncomp_crc32 = MZ_CRC32_INIT; mz_bool has_data_descriptor; mz_uint32 local_header_bit_flags; mz_zip_array file_data_array; mz_zip_array_init(&file_data_array, 1); if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (file_index > pZip->m_total_files) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState = pZip->m_pState; pCentral_dir_header = mz_zip_get_cdh(pZip, file_index); if (!mz_zip_file_stat_internal(pZip, file_index, pCentral_dir_header, &file_stat, &found_zip64_ext_data_in_cdir)) return MZ_FALSE; /* A directory or zero length file */ if ((file_stat.m_is_directory) || (!file_stat.m_uncomp_size)) return MZ_TRUE; /* Encryption and patch files are not supported. */ if (file_stat.m_is_encrypted) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); /* This function only supports stored and deflate. */ if ((file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); if (!file_stat.m_is_supported) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); /* Read and parse the local directory entry. */ local_header_ofs = file_stat.m_local_header_ofs; if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); local_header_filename_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); local_header_crc32 = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_CRC32_OFS); local_header_bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); has_data_descriptor = (local_header_bit_flags & 8) != 0; if (local_header_filename_len != strlen(file_stat.m_filename)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if ((local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if (!mz_zip_array_resize(pZip, &file_data_array, MZ_MAX(local_header_filename_len, local_header_extra_len), MZ_FALSE)) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); if (local_header_filename_len) { if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE, file_data_array.m_p, local_header_filename_len) != local_header_filename_len) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); goto handle_failure; } /* I've seen 1 archive that had the same pathname, but used backslashes in the local dir and forward slashes in the central dir. Do we care about this? For now, this case will fail validation. */ if (memcmp(file_stat.m_filename, file_data_array.m_p, local_header_filename_len) != 0) { mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); goto handle_failure; } } if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) { mz_uint32 extra_size_remaining = local_header_extra_len; const mz_uint8 *pExtra_data = (const mz_uint8 *)file_data_array.m_p; if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); goto handle_failure; } do { mz_uint32 field_id, field_data_size, field_total_size; if (extra_size_remaining < (sizeof(mz_uint16) * 2)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); field_id = MZ_READ_LE16(pExtra_data); field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); field_total_size = field_data_size + sizeof(mz_uint16) * 2; if (field_total_size > extra_size_remaining) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) { const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); if (field_data_size < sizeof(mz_uint64) * 2) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); goto handle_failure; } local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); found_zip64_ext_data_in_ldir = MZ_TRUE; break; } pExtra_data += field_total_size; extra_size_remaining -= field_total_size; } while (extra_size_remaining); } /* TODO: parse local header extra data when local_header_comp_size is 0xFFFFFFFF! (big_descriptor.zip) */ /* I've seen zips in the wild with the data descriptor bit set, but proper local header values and bogus data descriptors */ if ((has_data_descriptor) && (!local_header_comp_size) && (!local_header_crc32)) { mz_uint8 descriptor_buf[32]; mz_bool has_id; const mz_uint8 *pSrc; mz_uint32 file_crc32; mz_uint64 comp_size = 0, uncomp_size = 0; mz_uint32 num_descriptor_uint32s = ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) ? 6 : 4; if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size, descriptor_buf, sizeof(mz_uint32) * num_descriptor_uint32s) != (sizeof(mz_uint32) * num_descriptor_uint32s)) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); goto handle_failure; } has_id = (MZ_READ_LE32(descriptor_buf) == MZ_ZIP_DATA_DESCRIPTOR_ID); pSrc = has_id ? (descriptor_buf + sizeof(mz_uint32)) : descriptor_buf; file_crc32 = MZ_READ_LE32(pSrc); if ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) { comp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32)); uncomp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32) + sizeof(mz_uint64)); } else { comp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32)); uncomp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32) + sizeof(mz_uint32)); } if ((file_crc32 != file_stat.m_crc32) || (comp_size != file_stat.m_comp_size) || (uncomp_size != file_stat.m_uncomp_size)) { mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); goto handle_failure; } } else { if ((local_header_crc32 != file_stat.m_crc32) || (local_header_comp_size != file_stat.m_comp_size) || (local_header_uncomp_size != file_stat.m_uncomp_size)) { mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); goto handle_failure; } } mz_zip_array_clear(pZip, &file_data_array); if ((flags & MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY) == 0) { if (!mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_compute_crc32_callback, &uncomp_crc32, 0)) return MZ_FALSE; /* 1 more check to be sure, although the extract checks too. */ if (uncomp_crc32 != file_stat.m_crc32) { mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); return MZ_FALSE; } } return MZ_TRUE; handle_failure: mz_zip_array_clear(pZip, &file_data_array); return MZ_FALSE; } mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags) { mz_zip_internal_state *pState; uint32_t i; if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState = pZip->m_pState; /* Basic sanity checks */ if (!pState->m_zip64) { if (pZip->m_total_files > MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); if (pZip->m_archive_size > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); } else { if (pZip->m_total_files >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); } for (i = 0; i < pZip->m_total_files; i++) { if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags) { mz_uint32 found_index; mz_zip_archive_file_stat stat; if (!mz_zip_reader_file_stat(pZip, i, &stat)) return MZ_FALSE; if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, NULL, 0, &found_index)) return MZ_FALSE; /* This check can fail if there are duplicate filenames in the archive (which we don't check for when writing - that's up to the user) */ if (found_index != i) return mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); } if (!mz_zip_validate_file(pZip, i, flags)) return MZ_FALSE; } return MZ_TRUE; } mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr) { mz_bool success = MZ_TRUE; mz_zip_archive zip; mz_zip_error actual_err = MZ_ZIP_NO_ERROR; if ((!pMem) || (!size)) { if (pErr) *pErr = MZ_ZIP_INVALID_PARAMETER; return MZ_FALSE; } mz_zip_zero_struct(&zip); if (!mz_zip_reader_init_mem(&zip, pMem, size, flags)) { if (pErr) *pErr = zip.m_last_error; return MZ_FALSE; } if (!mz_zip_validate_archive(&zip, flags)) { actual_err = zip.m_last_error; success = MZ_FALSE; } if (!mz_zip_reader_end_internal(&zip, success)) { if (!actual_err) actual_err = zip.m_last_error; success = MZ_FALSE; } if (pErr) *pErr = actual_err; return success; } #ifndef MINIZ_NO_STDIO mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr) { mz_bool success = MZ_TRUE; mz_zip_archive zip; mz_zip_error actual_err = MZ_ZIP_NO_ERROR; if (!pFilename) { if (pErr) *pErr = MZ_ZIP_INVALID_PARAMETER; return MZ_FALSE; } mz_zip_zero_struct(&zip); if (!mz_zip_reader_init_file_v2(&zip, pFilename, flags, 0, 0)) { if (pErr) *pErr = zip.m_last_error; return MZ_FALSE; } if (!mz_zip_validate_archive(&zip, flags)) { actual_err = zip.m_last_error; success = MZ_FALSE; } if (!mz_zip_reader_end_internal(&zip, success)) { if (!actual_err) actual_err = zip.m_last_error; success = MZ_FALSE; } if (pErr) *pErr = actual_err; return success; } #endif /* #ifndef MINIZ_NO_STDIO */ /* ------------------- .ZIP archive writing */ #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); } static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); p[2] = (mz_uint8)(v >> 16); p[3] = (mz_uint8)(v >> 24); } static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) { mz_write_le32(p, (mz_uint32)v); mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); } #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) #define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; mz_zip_internal_state *pState = pZip->m_pState; mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); if (!n) return 0; /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */ if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) { mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); return 0; } if (new_size > pState->m_mem_capacity) { void *pNew_block; size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); while (new_capacity < new_size) new_capacity *= 2; if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); return 0; } pState->m_pMem = pNew_block; pState->m_mem_capacity = new_capacity; } memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); pState->m_mem_size = (size_t)new_size; return n; } static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) { mz_zip_internal_state *pState; mz_bool status = MZ_TRUE; if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) { if (set_last_error) mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return MZ_FALSE; } pState = pZip->m_pState; pZip->m_pState = NULL; mz_zip_array_clear(pZip, &pState->m_central_dir); mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); #ifndef MINIZ_NO_STDIO if (pState->m_pFile) { if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) { if (MZ_FCLOSE(pState->m_pFile) == EOF) { if (set_last_error) mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); status = MZ_FALSE; } } pState->m_pFile = NULL; } #endif /* #ifndef MINIZ_NO_STDIO */ if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); pState->m_pMem = NULL; } pZip->m_pFree(pZip->m_pAlloc_opaque, pState); pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; return status; } mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) { mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) { if (!pZip->m_pRead) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); } if (pZip->m_file_offset_alignment) { /* Ensure user specified file offset alignment is a power of 2. */ if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); } if (!pZip->m_pAlloc) pZip->m_pAlloc = miniz_def_alloc_func; if (!pZip->m_pFree) pZip->m_pFree = miniz_def_free_func; if (!pZip->m_pRealloc) pZip->m_pRealloc = miniz_def_realloc_func; pZip->m_archive_size = existing_size; pZip->m_central_directory_file_ofs = 0; pZip->m_total_files = 0; if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); pZip->m_pState->m_zip64 = zip64; pZip->m_pState->m_zip64_has_extended_info_fields = zip64; pZip->m_zip_type = MZ_ZIP_TYPE_USER; pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; return MZ_TRUE; } mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) { return mz_zip_writer_init_v2(pZip, existing_size, 0); } mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) { pZip->m_pWrite = mz_zip_heap_write_func; pZip->m_pNeeds_keepalive = NULL; if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) pZip->m_pRead = mz_zip_mem_read_func; pZip->m_pIO_opaque = pZip; if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) return MZ_FALSE; pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) { if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) { mz_zip_writer_end_internal(pZip, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } pZip->m_pState->m_mem_capacity = initial_allocation_size; } return MZ_TRUE; } mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) { return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); } #ifndef MINIZ_NO_STDIO static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); file_ofs += pZip->m_pState->m_file_archive_start_ofs; if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) { mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); return 0; } return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); } mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) { return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); } mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) { MZ_FILE *pFile; pZip->m_pWrite = mz_zip_file_write_func; pZip->m_pNeeds_keepalive = NULL; if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) pZip->m_pRead = mz_zip_file_read_func; pZip->m_pIO_opaque = pZip; if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) return MZ_FALSE; if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) { mz_zip_writer_end(pZip); return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); } pZip->m_pState->m_pFile = pFile; pZip->m_zip_type = MZ_ZIP_TYPE_FILE; if (size_to_reserve_at_beginning) { mz_uint64 cur_ofs = 0; char buf[4096]; MZ_CLEAR_OBJ(buf); do { size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) { mz_zip_writer_end(pZip); return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_ofs += n; size_to_reserve_at_beginning -= n; } while (size_to_reserve_at_beginning); } return MZ_TRUE; } mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) { pZip->m_pWrite = mz_zip_file_write_func; pZip->m_pNeeds_keepalive = NULL; if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) pZip->m_pRead = mz_zip_file_read_func; pZip->m_pIO_opaque = pZip; if (!mz_zip_writer_init_v2(pZip, 0, flags)) return MZ_FALSE; pZip->m_pState->m_pFile = pFile; pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; return MZ_TRUE; } #endif /* #ifndef MINIZ_NO_STDIO */ mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) { mz_zip_internal_state *pState; if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) { /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */ if (!pZip->m_pState->m_zip64) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); } /* No sense in trying to write to an archive that's already at the support max size */ if (pZip->m_pState->m_zip64) { if (pZip->m_total_files == MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } else { if (pZip->m_total_files == MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); } pState = pZip->m_pState; if (pState->m_pFile) { #ifdef MINIZ_NO_STDIO (void)pFilename; return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); #else if (pZip->m_pIO_opaque != pZip) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) { if (!pFilename) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) { /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ mz_zip_reader_end_internal(pZip, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); } } pZip->m_pWrite = mz_zip_file_write_func; pZip->m_pNeeds_keepalive = NULL; #endif /* #ifdef MINIZ_NO_STDIO */ } else if (pState->m_pMem) { /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */ if (pZip->m_pIO_opaque != pZip) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState->m_mem_capacity = pState->m_mem_size; pZip->m_pWrite = mz_zip_heap_write_func; pZip->m_pNeeds_keepalive = NULL; } /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ else if (!pZip->m_pWrite) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); /* Start writing new files at the archive's current central directory location. */ /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */ pZip->m_archive_size = pZip->m_central_directory_file_ofs; pZip->m_central_directory_file_ofs = 0; /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */ /* TODO: We could easily maintain the sorted central directory offsets. */ mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; return MZ_TRUE; } mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) { return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); } /* TODO: pArchive_name is a terrible name here! */ mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) { return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); } typedef struct { mz_zip_archive *m_pZip; mz_uint64 m_cur_archive_file_ofs; mz_uint64 m_comp_size; } mz_zip_writer_add_state; static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) { mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) return MZ_FALSE; pState->m_cur_archive_file_ofs += len; pState->m_comp_size += len; return MZ_TRUE; } #define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) #define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) { mz_uint8 *pDst = pBuf; mz_uint32 field_size = 0; MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); MZ_WRITE_LE16(pDst + 2, 0); pDst += sizeof(mz_uint16) * 2; if (pUncomp_size) { MZ_WRITE_LE64(pDst, *pUncomp_size); pDst += sizeof(mz_uint64); field_size += sizeof(mz_uint64); } if (pComp_size) { MZ_WRITE_LE64(pDst, *pComp_size); pDst += sizeof(mz_uint64); field_size += sizeof(mz_uint64); } if (pLocal_header_ofs) { MZ_WRITE_LE64(pDst, *pLocal_header_ofs); pDst += sizeof(mz_uint64); field_size += sizeof(mz_uint64); } MZ_WRITE_LE16(pBuf + 2, field_size); return (mz_uint32)(pDst - pBuf); } static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) { (void)pZip; memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); return MZ_TRUE; } static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) { (void)pZip; memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); return MZ_TRUE; } static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes, const char *user_extra_data, mz_uint user_extra_data_len) { mz_zip_internal_state *pState = pZip->m_pState; mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; size_t orig_central_dir_size = pState->m_central_dir.m_size; mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; if (!pZip->m_pState->m_zip64) { if (local_header_ofs > 0xFFFFFFFF) return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); } /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size + user_extra_data_len, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) { /* Try to resize the central directory array back into its original state. */ mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } return MZ_TRUE; } static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) { /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */ if (*pArchive_name == '/') return MZ_FALSE; while (*pArchive_name) { if ((*pArchive_name == '\\') || (*pArchive_name == ':')) return MZ_FALSE; pArchive_name++; } return MZ_TRUE; } static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) { mz_uint32 n; if (!pZip->m_file_offset_alignment) return 0; n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); } static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) { char buf[4096]; memset(buf, 0, MZ_MIN(sizeof(buf), n)); while (n) { mz_uint32 s = MZ_MIN(sizeof(buf), n); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_file_ofs += s; n -= s; } return MZ_TRUE; } mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) { return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); } mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) { mz_uint16 method = 0, dos_time = 0, dos_date = 0; mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; size_t archive_name_size; mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; tdefl_compressor *pComp = NULL; mz_bool store_data_uncompressed; mz_zip_internal_state *pState; mz_uint8 *pExtra_data = NULL; mz_uint32 extra_size = 0; mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; mz_uint16 bit_flags = 0; if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; level = level_and_flags & 0xF; store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState = pZip->m_pState; if (pState->m_zip64) { if (pZip->m_total_files == MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } else { if (pZip->m_total_files == MZ_UINT16_MAX) { pState->m_zip64 = MZ_TRUE; /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ } if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) { pState->m_zip64 = MZ_TRUE; /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ } } if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!mz_zip_writer_validate_archive_name(pArchive_name)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); #ifndef MINIZ_NO_TIME if (last_modified != NULL) { mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); } else { MZ_TIME_T cur_time; time(&cur_time); mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); } #endif /* #ifndef MINIZ_NO_TIME */ archive_name_size = strlen(pArchive_name); if (archive_name_size > MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); if (!pState->m_zip64) { /* Bail early if the archive would obviously become too large */ if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) { pState->m_zip64 = MZ_TRUE; /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ } } if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) { /* Set DOS Subdirectory attribute bit. */ ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; /* Subdirectories cannot contain data. */ if ((buf_size) || (uncomp_size)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); } /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */ if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); if ((!store_data_uncompressed) && (buf_size)) { if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return MZ_FALSE; } local_dir_header_ofs += num_alignment_padding_bytes; if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } cur_archive_file_ofs += num_alignment_padding_bytes; MZ_CLEAR_OBJ(local_dir_header); if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { method = MZ_DEFLATED; } if (pState->m_zip64) { if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) { pExtra_data = extra_data; extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); } if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += sizeof(local_dir_header); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_archive_file_ofs += archive_name_size; if (pExtra_data != NULL) { if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += extra_size; } } else { if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += sizeof(local_dir_header); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_archive_file_ofs += archive_name_size; } if (user_extra_data_len > 0) { if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += user_extra_data_len; } if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); uncomp_size = buf_size; if (uncomp_size <= 3) { level = 0; store_data_uncompressed = MZ_TRUE; } } if (store_data_uncompressed) { if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_archive_file_ofs += buf_size; comp_size = buf_size; } else if (buf_size) { mz_zip_writer_add_state state; state.m_pZip = pZip; state.m_cur_archive_file_ofs = cur_archive_file_ofs; state.m_comp_size = 0; if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); } comp_size = state.m_comp_size; cur_archive_file_ofs = state.m_cur_archive_file_ofs; } pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); pComp = NULL; if (uncomp_size) { mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); if (pExtra_data == NULL) { if (comp_size > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); MZ_WRITE_LE32(local_dir_footer + 8, comp_size); MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); } else { MZ_WRITE_LE64(local_dir_footer + 8, comp_size); MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; } if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) return MZ_FALSE; cur_archive_file_ofs += local_dir_footer_size; } if (pExtra_data != NULL) { extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); } if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, user_extra_data_central, user_extra_data_central_len)) return MZ_FALSE; pZip->m_total_files++; pZip->m_archive_size = cur_archive_file_ofs; return MZ_TRUE; } #ifndef MINIZ_NO_STDIO mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) { mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0; size_t archive_name_size; mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; mz_uint8 *pExtra_data = NULL; mz_uint32 extra_size = 0; mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; mz_zip_internal_state *pState; if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; level = level_and_flags & 0xF; /* Sanity checks */ if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState = pZip->m_pState; if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX)) { /* Source file is too large for non-zip64 */ /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ pState->m_zip64 = MZ_TRUE; } /* We could support this, but why? */ if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!mz_zip_writer_validate_archive_name(pArchive_name)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); if (pState->m_zip64) { if (pZip->m_total_files == MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } else { if (pZip->m_total_files == MZ_UINT16_MAX) { pState->m_zip64 = MZ_TRUE; /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ } } archive_name_size = strlen(pArchive_name); if (archive_name_size > MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); if (!pState->m_zip64) { /* Bail early if the archive would obviously become too large */ if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) { pState->m_zip64 = MZ_TRUE; /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ } } #ifndef MINIZ_NO_TIME if (pFile_time) { mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); } #endif if (uncomp_size <= 3) level = 0; if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) { return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_archive_file_ofs += num_alignment_padding_bytes; local_dir_header_ofs = cur_archive_file_ofs; if (pZip->m_file_offset_alignment) { MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } if (uncomp_size && level) { method = MZ_DEFLATED; } MZ_CLEAR_OBJ(local_dir_header); if (pState->m_zip64) { if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) { pExtra_data = extra_data; extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); } if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += sizeof(local_dir_header); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) { return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_archive_file_ofs += archive_name_size; if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += extra_size; } else { if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += sizeof(local_dir_header); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) { return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_archive_file_ofs += archive_name_size; } if (user_extra_data_len > 0) { if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += user_extra_data_len; } if (uncomp_size) { mz_uint64 uncomp_remaining = uncomp_size; void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); if (!pRead_buf) { return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (!level) { while (uncomp_remaining) { mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); } uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); uncomp_remaining -= n; cur_archive_file_ofs += n; } comp_size = uncomp_size; } else { mz_bool result = MZ_FALSE; mz_zip_writer_add_state state; tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); if (!pComp) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } state.m_pZip = pZip; state.m_cur_archive_file_ofs = cur_archive_file_ofs; state.m_comp_size = 0; if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); } for (;;) { size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); tdefl_status status; tdefl_flush flush = TDEFL_NO_FLUSH; if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); break; } uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); uncomp_remaining -= in_buf_size; if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) flush = TDEFL_FULL_FLUSH; status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH); if (status == TDEFL_STATUS_DONE) { result = MZ_TRUE; break; } else if (status != TDEFL_STATUS_OKAY) { mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); break; } } pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); if (!result) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); return MZ_FALSE; } comp_size = state.m_comp_size; cur_archive_file_ofs = state.m_cur_archive_file_ofs; } pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); } { mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); if (pExtra_data == NULL) { if (comp_size > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); MZ_WRITE_LE32(local_dir_footer + 8, comp_size); MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); } else { MZ_WRITE_LE64(local_dir_footer + 8, comp_size); MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; } if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) return MZ_FALSE; cur_archive_file_ofs += local_dir_footer_size; } if (pExtra_data != NULL) { extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); } if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, user_extra_data_central, user_extra_data_central_len)) return MZ_FALSE; pZip->m_total_files++; pZip->m_archive_size = cur_archive_file_ofs; return MZ_TRUE; } mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) { MZ_FILE *pSrc_file = NULL; mz_uint64 uncomp_size = 0; MZ_TIME_T file_modified_time; MZ_TIME_T *pFile_time = NULL; mz_bool status; memset(&file_modified_time, 0, sizeof(file_modified_time)); #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) pFile_time = &file_modified_time; if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); #endif pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); if (!pSrc_file) return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); MZ_FSEEK64(pSrc_file, 0, SEEK_END); uncomp_size = MZ_FTELL64(pSrc_file); MZ_FSEEK64(pSrc_file, 0, SEEK_SET); status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); MZ_FCLOSE(pSrc_file); return status; } #endif /* #ifndef MINIZ_NO_STDIO */ static mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, uint32_t ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start) { /* + 64 should be enough for any new zip64 data */ if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE)) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); mz_zip_array_resize(pZip, pNew_ext, 0, MZ_FALSE); if ((pUncomp_size) || (pComp_size) || (pLocal_header_ofs) || (pDisk_start)) { mz_uint8 new_ext_block[64]; mz_uint8 *pDst = new_ext_block; mz_write_le16(pDst, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); mz_write_le16(pDst + sizeof(mz_uint16), 0); pDst += sizeof(mz_uint16) * 2; if (pUncomp_size) { mz_write_le64(pDst, *pUncomp_size); pDst += sizeof(mz_uint64); } if (pComp_size) { mz_write_le64(pDst, *pComp_size); pDst += sizeof(mz_uint64); } if (pLocal_header_ofs) { mz_write_le64(pDst, *pLocal_header_ofs); pDst += sizeof(mz_uint64); } if (pDisk_start) { mz_write_le32(pDst, *pDisk_start); pDst += sizeof(mz_uint32); } mz_write_le16(new_ext_block + sizeof(mz_uint16), (mz_uint16)((pDst - new_ext_block) - sizeof(mz_uint16) * 2)); if (!mz_zip_array_push_back(pZip, pNew_ext, new_ext_block, pDst - new_ext_block)) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if ((pExt) && (ext_len)) { mz_uint32 extra_size_remaining = ext_len; const mz_uint8 *pExtra_data = pExt; do { mz_uint32 field_id, field_data_size, field_total_size; if (extra_size_remaining < (sizeof(mz_uint16) * 2)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); field_id = MZ_READ_LE16(pExtra_data); field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); field_total_size = field_data_size + sizeof(mz_uint16) * 2; if (field_total_size > extra_size_remaining) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if (field_id != MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) { if (!mz_zip_array_push_back(pZip, pNew_ext, pExtra_data, field_total_size)) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } pExtra_data += field_total_size; extra_size_remaining -= field_total_size; } while (extra_size_remaining); } return MZ_TRUE; } /* TODO: This func is now pretty freakin complex due to zip64, split it up? */ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index) { mz_uint n, bit_flags, num_alignment_padding_bytes, src_central_dir_following_data_size; mz_uint64 src_archive_bytes_remaining, local_dir_header_ofs; mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; mz_uint8 new_central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; size_t orig_central_dir_size; mz_zip_internal_state *pState; void *pBuf; const mz_uint8 *pSrc_central_header; mz_zip_archive_file_stat src_file_stat; mz_uint32 src_filename_len, src_comment_len, src_ext_len; mz_uint32 local_header_filename_size, local_header_extra_len; mz_uint64 local_header_comp_size, local_header_uncomp_size; mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; /* Sanity checks */ if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pSource_zip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState = pZip->m_pState; /* Don't support copying files from zip64 archives to non-zip64, even though in some cases this is possible */ if ((pSource_zip->m_pState->m_zip64) && (!pZip->m_pState->m_zip64)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); /* Get pointer to the source central dir header and crack it */ if (NULL == (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index))) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); src_filename_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS); src_comment_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); src_ext_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS); src_central_dir_following_data_size = src_filename_len + src_ext_len + src_comment_len; /* TODO: We don't support central dir's >= MZ_UINT32_MAX bytes right now (+32 fudge factor in case we need to add more extra data) */ if ((pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + 32) >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); if (!pState->m_zip64) { if (pZip->m_total_files == MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } else { /* TODO: Our zip64 support still has some 32-bit limits that may not be worth fixing. */ if (pZip->m_total_files == MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } if (!mz_zip_file_stat_internal(pSource_zip, src_file_index, pSrc_central_header, &src_file_stat, NULL)) return MZ_FALSE; cur_src_file_ofs = src_file_stat.m_local_header_ofs; cur_dst_file_ofs = pZip->m_archive_size; /* Read the source archive's local dir header */ if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; /* Compute the total size we need to copy (filename+extra data+compressed data) */ local_header_filename_size = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); src_archive_bytes_remaining = local_header_filename_size + local_header_extra_len + src_file_stat.m_comp_size; /* Try to find a zip64 extended information field */ if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) { mz_zip_array file_data_array; const mz_uint8 *pExtra_data; mz_uint32 extra_size_remaining = local_header_extra_len; mz_zip_array_init(&file_data_array, 1); if (!mz_zip_array_resize(pZip, &file_data_array, local_header_extra_len, MZ_FALSE)) { return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, src_file_stat.m_local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_size, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) { mz_zip_array_clear(pZip, &file_data_array); return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); } pExtra_data = (const mz_uint8 *)file_data_array.m_p; do { mz_uint32 field_id, field_data_size, field_total_size; if (extra_size_remaining < (sizeof(mz_uint16) * 2)) { mz_zip_array_clear(pZip, &file_data_array); return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); } field_id = MZ_READ_LE16(pExtra_data); field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); field_total_size = field_data_size + sizeof(mz_uint16) * 2; if (field_total_size > extra_size_remaining) { mz_zip_array_clear(pZip, &file_data_array); return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); } if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) { const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); if (field_data_size < sizeof(mz_uint64) * 2) { mz_zip_array_clear(pZip, &file_data_array); return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); } local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ found_zip64_ext_data_in_ldir = MZ_TRUE; break; } pExtra_data += field_total_size; extra_size_remaining -= field_total_size; } while (extra_size_remaining); mz_zip_array_clear(pZip, &file_data_array); } if (!pState->m_zip64) { /* Try to detect if the new archive will most likely wind up too big and bail early (+(sizeof(mz_uint32) * 4) is for the optional descriptor which could be present, +64 is a fudge factor). */ /* We also check when the archive is finalized so this doesn't need to be perfect. */ mz_uint64 approx_new_archive_size = cur_dst_file_ofs + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + src_archive_bytes_remaining + (sizeof(mz_uint32) * 4) + pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 64; if (approx_new_archive_size >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); } /* Write dest archive padding */ if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) return MZ_FALSE; cur_dst_file_ofs += num_alignment_padding_bytes; local_dir_header_ofs = cur_dst_file_ofs; if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } /* The original zip's local header+ext block doesn't change, even with zip64, so we can just copy it over to the dest zip */ if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; /* Copy over the source archive bytes to the dest archive, also ensure we have enough buf space to handle optional data descriptor */ if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(32U, MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining))))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); while (src_archive_bytes_remaining) { n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining); if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); } cur_src_file_ofs += n; if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_dst_file_ofs += n; src_archive_bytes_remaining -= n; } /* Now deal with the optional data descriptor */ bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); if (bit_flags & 8) { /* Copy data descriptor */ if ((pSource_zip->m_pState->m_zip64) || (found_zip64_ext_data_in_ldir)) { /* src is zip64, dest must be zip64 */ /* name uint32_t's */ /* id 1 (optional in zip64?) */ /* crc 1 */ /* comp_size 2 */ /* uncomp_size 2 */ if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, (sizeof(mz_uint32) * 6)) != (sizeof(mz_uint32) * 6)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); } n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID) ? 6 : 5); } else { /* src is NOT zip64 */ mz_bool has_id; if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); } has_id = (MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID); if (pZip->m_pState->m_zip64) { /* dest is zip64, so upgrade the data descriptor */ const mz_uint32 *pSrc_descriptor = (const mz_uint32 *)((const mz_uint8 *)pBuf + (has_id ? sizeof(mz_uint32) : 0)); const mz_uint32 src_crc32 = pSrc_descriptor[0]; const mz_uint64 src_comp_size = pSrc_descriptor[1]; const mz_uint64 src_uncomp_size = pSrc_descriptor[2]; mz_write_le32((mz_uint8 *)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID); mz_write_le32((mz_uint8 *)pBuf + sizeof(mz_uint32) * 1, src_crc32); mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 2, src_comp_size); mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 4, src_uncomp_size); n = sizeof(mz_uint32) * 6; } else { /* dest is NOT zip64, just copy it as-is */ n = sizeof(mz_uint32) * (has_id ? 4 : 3); } } if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_src_file_ofs += n; cur_dst_file_ofs += n; } pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); /* Finally, add the new central dir header */ orig_central_dir_size = pState->m_central_dir.m_size; memcpy(new_central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); if (pState->m_zip64) { /* This is the painful part: We need to write a new central dir header + ext block with updated zip64 fields, and ensure the old fields (if any) are not included. */ const mz_uint8 *pSrc_ext = pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len; mz_zip_array new_ext_block; mz_zip_array_init(&new_ext_block, sizeof(mz_uint8)); MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_UINT32_MAX); MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_UINT32_MAX); MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_UINT32_MAX); if (!mz_zip_writer_update_zip64_extension_block(&new_ext_block, pZip, pSrc_ext, src_ext_len, &src_file_stat.m_comp_size, &src_file_stat.m_uncomp_size, &local_dir_header_ofs, NULL)) { mz_zip_array_clear(pZip, &new_ext_block); return MZ_FALSE; } MZ_WRITE_LE16(new_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS, new_ext_block.m_size); if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) { mz_zip_array_clear(pZip, &new_ext_block); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_filename_len)) { mz_zip_array_clear(pZip, &new_ext_block); mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_ext_block.m_p, new_ext_block.m_size)) { mz_zip_array_clear(pZip, &new_ext_block); mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len + src_ext_len, src_comment_len)) { mz_zip_array_clear(pZip, &new_ext_block); mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } mz_zip_array_clear(pZip, &new_ext_block); } else { /* sanity checks */ if (cur_dst_file_ofs > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); if (local_dir_header_ofs >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_central_dir_following_data_size)) { mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } } /* This shouldn't trigger unless we screwed up during the initial sanity checks */ if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) { /* TODO: Support central dirs >= 32-bits in size */ mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); } n = (mz_uint32)orig_central_dir_size; if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) { mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } pZip->m_total_files++; pZip->m_archive_size = cur_dst_file_ofs; return MZ_TRUE; } mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) { mz_zip_internal_state *pState; mz_uint64 central_dir_ofs, central_dir_size; mz_uint8 hdr[256]; if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState = pZip->m_pState; if (pState->m_zip64) { if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX)) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } else { if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } central_dir_ofs = 0; central_dir_size = 0; if (pZip->m_total_files) { /* Write central directory */ central_dir_ofs = pZip->m_archive_size; central_dir_size = pState->m_central_dir.m_size; pZip->m_central_directory_file_ofs = central_dir_ofs; if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); pZip->m_archive_size += central_dir_size; } if (pState->m_zip64) { /* Write zip64 end of central directory header */ mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; MZ_CLEAR_OBJ(hdr); MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; /* Write zip64 end of central directory locator */ MZ_CLEAR_OBJ(hdr); MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; } /* Write end of central directory record */ MZ_CLEAR_OBJ(hdr); MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); #ifndef MINIZ_NO_STDIO if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); #endif /* #ifndef MINIZ_NO_STDIO */ pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; return MZ_TRUE; } mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) { if ((!ppBuf) || (!pSize)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); *ppBuf = NULL; *pSize = 0; if ((!pZip) || (!pZip->m_pState)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (pZip->m_pWrite != mz_zip_heap_write_func) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!mz_zip_writer_finalize_archive(pZip)) return MZ_FALSE; *ppBuf = pZip->m_pState->m_pMem; *pSize = pZip->m_pState->m_mem_size; pZip->m_pState->m_pMem = NULL; pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; return MZ_TRUE; } mz_bool mz_zip_writer_end(mz_zip_archive *pZip) { return mz_zip_writer_end_internal(pZip, MZ_TRUE); } #ifndef MINIZ_NO_STDIO mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) { return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); } mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) { mz_bool status, created_new_archive = MZ_FALSE; mz_zip_archive zip_archive; struct MZ_FILE_STAT_STRUCT file_stat; mz_zip_error actual_err = MZ_ZIP_NO_ERROR; mz_zip_zero_struct(&zip_archive); if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) { if (pErr) *pErr = MZ_ZIP_INVALID_PARAMETER; return MZ_FALSE; } if (!mz_zip_writer_validate_archive_name(pArchive_name)) { if (pErr) *pErr = MZ_ZIP_INVALID_FILENAME; return MZ_FALSE; } /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */ /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) { /* Create a new archive. */ if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) { if (pErr) *pErr = zip_archive.m_last_error; return MZ_FALSE; } created_new_archive = MZ_TRUE; } else { /* Append to an existing archive. */ if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) { if (pErr) *pErr = zip_archive.m_last_error; return MZ_FALSE; } if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) { if (pErr) *pErr = zip_archive.m_last_error; mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); return MZ_FALSE; } } status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); actual_err = zip_archive.m_last_error; /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */ if (!mz_zip_writer_finalize_archive(&zip_archive)) { if (!actual_err) actual_err = zip_archive.m_last_error; status = MZ_FALSE; } if (!mz_zip_writer_end_internal(&zip_archive, status)) { if (!actual_err) actual_err = zip_archive.m_last_error; status = MZ_FALSE; } if ((!status) && (created_new_archive)) { /* It's a new archive and something went wrong, so just delete it. */ int ignoredStatus = MZ_DELETE_FILE(pZip_filename); (void)ignoredStatus; } if (pErr) *pErr = actual_err; return status; } void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) { mz_uint32 file_index; mz_zip_archive zip_archive; void *p = NULL; if (pSize) *pSize = 0; if ((!pZip_filename) || (!pArchive_name)) { if (pErr) *pErr = MZ_ZIP_INVALID_PARAMETER; return NULL; } mz_zip_zero_struct(&zip_archive); if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) { if (pErr) *pErr = zip_archive.m_last_error; return NULL; } if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) { p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); } mz_zip_reader_end_internal(&zip_archive, p != NULL); if (pErr) *pErr = zip_archive.m_last_error; return p; } void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) { return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); } #endif /* #ifndef MINIZ_NO_STDIO */ #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ /* ------------------- Misc utils */ mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) { return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; } mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) { return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; } mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) { mz_zip_error prev_err; if (!pZip) return MZ_ZIP_INVALID_PARAMETER; prev_err = pZip->m_last_error; pZip->m_last_error = err_num; return prev_err; } mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) { if (!pZip) return MZ_ZIP_INVALID_PARAMETER; return pZip->m_last_error; } mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) { return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); } mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) { mz_zip_error prev_err; if (!pZip) return MZ_ZIP_INVALID_PARAMETER; prev_err = pZip->m_last_error; pZip->m_last_error = MZ_ZIP_NO_ERROR; return prev_err; } const char *mz_zip_get_error_string(mz_zip_error mz_err) { switch (mz_err) { case MZ_ZIP_NO_ERROR: return "no error"; case MZ_ZIP_UNDEFINED_ERROR: return "undefined error"; case MZ_ZIP_TOO_MANY_FILES: return "too many files"; case MZ_ZIP_FILE_TOO_LARGE: return "file too large"; case MZ_ZIP_UNSUPPORTED_METHOD: return "unsupported method"; case MZ_ZIP_UNSUPPORTED_ENCRYPTION: return "unsupported encryption"; case MZ_ZIP_UNSUPPORTED_FEATURE: return "unsupported feature"; case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: return "failed finding central directory"; case MZ_ZIP_NOT_AN_ARCHIVE: return "not a ZIP archive"; case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: return "invalid header or archive is corrupted"; case MZ_ZIP_UNSUPPORTED_MULTIDISK: return "unsupported multidisk archive"; case MZ_ZIP_DECOMPRESSION_FAILED: return "decompression failed or archive is corrupted"; case MZ_ZIP_COMPRESSION_FAILED: return "compression failed"; case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: return "unexpected decompressed size"; case MZ_ZIP_CRC_CHECK_FAILED: return "CRC-32 check failed"; case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: return "unsupported central directory size"; case MZ_ZIP_ALLOC_FAILED: return "allocation failed"; case MZ_ZIP_FILE_OPEN_FAILED: return "file open failed"; case MZ_ZIP_FILE_CREATE_FAILED: return "file create failed"; case MZ_ZIP_FILE_WRITE_FAILED: return "file write failed"; case MZ_ZIP_FILE_READ_FAILED: return "file read failed"; case MZ_ZIP_FILE_CLOSE_FAILED: return "file close failed"; case MZ_ZIP_FILE_SEEK_FAILED: return "file seek failed"; case MZ_ZIP_FILE_STAT_FAILED: return "file stat failed"; case MZ_ZIP_INVALID_PARAMETER: return "invalid parameter"; case MZ_ZIP_INVALID_FILENAME: return "invalid filename"; case MZ_ZIP_BUF_TOO_SMALL: return "buffer too small"; case MZ_ZIP_INTERNAL_ERROR: return "internal error"; case MZ_ZIP_FILE_NOT_FOUND: return "file not found"; case MZ_ZIP_ARCHIVE_TOO_LARGE: return "archive is too large"; case MZ_ZIP_VALIDATION_FAILED: return "validation failed"; case MZ_ZIP_WRITE_CALLBACK_FAILED: return "write calledback failed"; default: break; } return "unknown error"; } /* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */ mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) { if ((!pZip) || (!pZip->m_pState)) return MZ_FALSE; return pZip->m_pState->m_zip64; } size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) { if ((!pZip) || (!pZip->m_pState)) return 0; return pZip->m_pState->m_central_dir.m_size; } mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) { return pZip ? pZip->m_total_files : 0; } mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) { if (!pZip) return 0; return pZip->m_archive_size; } mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) { if ((!pZip) || (!pZip->m_pState)) return 0; return pZip->m_pState->m_file_archive_start_ofs; } MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) { if ((!pZip) || (!pZip->m_pState)) return 0; return pZip->m_pState->m_pFile; } size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) { if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); } mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) { mz_uint n; const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); if (!p) { if (filename_buf_size) pFilename[0] = '\0'; mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return 0; } n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); if (filename_buf_size) { n = MZ_MIN(n, filename_buf_size - 1); memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pFilename[n] = '\0'; } return n + 1; } mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) { return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); } mz_bool mz_zip_end(mz_zip_archive *pZip) { if (!pZip) return MZ_FALSE; if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) return mz_zip_reader_end(pZip); #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) return mz_zip_writer_end(pZip); #endif return MZ_FALSE; } #ifdef __cplusplus } #endif #endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ libminizinc-2.4.2/lib/model.cpp000066400000000000000000000461001360574160400164070ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #undef MZN_DEBUG_FUNCTION_REGISTRY namespace MiniZinc { Model::FnEntry::FnEntry(FunctionI* fi0) : t(fi0->params().size()), fi(fi0), isPolymorphic(false) { for (unsigned int i=0; iparams().size(); i++) { t[i] = fi->params()[i]->type(); isPolymorphic |= (t[i].bt()==Type::BT_TOP); } } bool Model::FnEntry::operator<(const Model::FnEntry& f) const { assert(!compare(*this,f) || !compare(f,*this)); return compare(*this, f); } bool Model::FnEntry::compare(const Model::FnEntry& e1, const Model::FnEntry& e2) { if (e1.t.size() < e2.t.size()) { return true; } if (e1.t.size() == e2.t.size()) { for (unsigned int i=0; idyn_cast()) { if (ii->own() && ii->m()) { delete ii->m(); ii->m(NULL); } } } GC::remove(this); } VarDeclIterator Model::begin_vardecls(void) { return VarDeclIterator(this, begin()); } VarDeclIterator Model::end_vardecls(void) { return VarDeclIterator(this, end()); } ConstraintIterator Model::begin_constraints(void) { return ConstraintIterator(this, begin()); } ConstraintIterator Model::end_constraints(void) { return ConstraintIterator(this, end()); } FunctionIterator Model::begin_functions(void) { return FunctionIterator(this, begin()); } FunctionIterator Model::end_functions(void) { return FunctionIterator(this, end()); } SolveI* Model::solveItem() { return _solveItem; } OutputI* Model::outputItem() { return _outputItem; } void Model::addItem(Item* i) { _items.push_back(i); if (i->isa()) { Model* m = this; while (m->_parent) m = m->_parent; m->_solveItem = i->cast(); } else if (i->isa()) { Model* m = this; while (m->_parent) m = m->_parent; m->_outputItem = i->cast(); } } void Model::setOutputItem(OutputI* oi) { Model* m = this; while (m->_parent) m = m->_parent; m->_outputItem = oi; } namespace { /// Return lowest possible base type given other type-inst restrictions Type::BaseType lowestBt(const Type& t) { if (t.st()==Type::ST_SET && t.ti()==Type::TI_VAR) return Type::BT_INT; return Type::BT_BOOL; } /// Return highest possible base type given other type-inst restrictions Type::BaseType highestBt(const Type& t) { if (t.st()==Type::ST_SET && t.ti()==Type::TI_VAR) return Type::BT_INT; if (t.ti()==Type::TI_VAR || t.st()==Type::ST_SET) return Type::BT_FLOAT; return Type::BT_ANN; } } void Model::addPolymorphicInstances(Model::FnEntry& fe, std::vector& entries) { entries.push_back(fe); if (fe.isPolymorphic) { FnEntry cur = fe; std::vector > type_ids; // First step: initialise all type variables to bool // and collect them in the stack vector for (unsigned int i=0; i t; for (unsigned int j=i; jparams()[i]->ti()->domain() && cur.fi->params()[i]->ti()->domain()->isa()); if (cur.fi->params()[j]->ti()->domain() && cur.fi->params()[j]->ti()->domain()->isa()) { TIId* id0 = cur.fi->params()[i]->ti()->domain()->cast(); TIId* id1 = cur.fi->params()[j]->ti()->domain()->cast(); if (id0->v()==id1->v()) { // Found parameter with same type variable // Initialise to lowest concrete base type (bool) cur.t[j].bt(lowestBt(cur.t[j])); t.push_back(&cur.t[j]); } } } type_ids.push_back(t); } } std::vector stack; for (unsigned int i=0; i(type_ids.size())-1; while (!stack.empty()) { if (stack.back()==final_id) { // If this instance isn't in entries yet, add it bool alreadyDefined = false; for (unsigned int i=0; ist(Type::ST_SET); type_ids[stack.back()][i]->bt(lowestBt(*type_ids[stack.back()][i])); } } else { // Increment type of current item Type::BaseType nextType = static_cast(back_t.bt()+1); for (unsigned int i=0; ibt(nextType); } } // Reset types of all further items and push them for (unsigned int i=stack.back()+1; ibt(lowestBt(*type_ids[i][j])); } stack.push_back(i); } } } } } void Model::registerFn(EnvI& env, FunctionI* fi) { Model* m = this; while (m->_parent) m = m->_parent; FnMap::iterator i_id = m->fnmap.find(fi->id()); if (i_id == m->fnmap.end()) { // new element std::vector v; FnEntry fe(fi); addPolymorphicInstances(fe, v); m->fnmap.insert(std::pair >(fi->id(),v)); } else { // add to list of existing elements std::vector& v = i_id->second; for (unsigned int i=0; iparams().size() == fi->params().size()) { bool alleq=true; for (unsigned int j=0; jparams().size(); j++) { Type t1 = v[i].fi->params()[j]->type(); Type t2 = fi->params()[j]->type(); t1.enumId(0); t2.enumId(0); if (t1 != t2) { alleq=false; break; } } if (alleq) { if (v[i].fi->e() && fi->e() && !v[i].isPolymorphic) { throw TypeError(env, fi->loc(), "function with the same type already defined in " +v[i].fi->loc().toString()); } else { if (fi->e() || v[i].isPolymorphic) { if (Call* deprecated = v[i].fi->ann().getCall(constants().ann.mzn_deprecated)) { fi->ann().add(deprecated); } v[i] = fi; } else if (Call* deprecated = fi->ann().getCall(constants().ann.mzn_deprecated)) { v[i].fi->ann().add(deprecated); } return; } } } } FnEntry fe(fi); addPolymorphicInstances(fe, v); } if (fi->id()=="mzn_reverse_map_var") { if (fi->params().size() != 1 || fi->ti()->type() != Type::varbool()) { throw TypeError(env, fi->loc(), "functions called `mzn_reverse_map_var` must have a single argument and return type var bool"); } Type t = fi->params()[0]->type(); revmapmap.insert(std::pair(t.toInt(),fi)); } } FunctionI* Model::matchFn(EnvI& env, const ASTString& id, const std::vector& t, bool strictEnums) { if (id==constants().var_redef->id()) return constants().var_redef; Model* m = this; while (m->_parent) m = m->_parent; FnMap::iterator i_id = m->fnmap.find(id); if (i_id == m->fnmap.end()) { return NULL; } std::vector& v = i_id->second; for (unsigned int i=0; i& fi_t = v[i].t; #ifdef MZN_DEBUG_FUNCTION_REGISTRY std::cerr << "try " << *v[i].fi; #endif if (fi_t.size() == t.size()) { bool match=true; for (unsigned int j=0; j::const_iterator cit = it->second.begin(); cit != it->second.end(); ++cit) { if ((*cit).fi->from_stdlib()) { m->registerFn(env, (*cit).fi); } } } } void Model::sortFn(void) { Model* m = this; while (m->_parent) m = m->_parent; for (FnMap::iterator it=m->fnmap.begin(); it!=m->fnmap.end(); ++it) { // Sort all functions by type std::sort(it->second.begin(),it->second.end()); } } void Model::fixFnMap(void) { Model* m = this; while (m->_parent) m = m->_parent; for (FnMap::iterator it=m->fnmap.begin(); it!=m->fnmap.end(); ++it) { for (unsigned int i=0; isecond.size(); i++) { for (unsigned int j=0; jsecond[i].t.size(); j++) { if (it->second[i].t[j].isunknown()) { it->second[i].t[j] = it->second[i].fi->params()[j]->type(); } } } } } void Model::checkFnOverloading(EnvI& env) { Model* m = this; while (m->_parent) m = m->_parent; for (FnMap::iterator it=m->fnmap.begin(); it!=m->fnmap.end(); ++it) { std::vector& fs = it->second; for (unsigned int i=0; iparams().size() != cmp->params().size()) break; bool allEqual = true; for (unsigned int i=0; iparams().size(); i++) { Type t1 = cur->params()[i]->type(); Type t2 = cmp->params()[i]->type(); t1.enumId(0); t2.enumId(0); if (t1!=t2) { allEqual = false; break; } } if (allEqual) throw TypeError(env,cur->loc(), "unsupported type of overloading. \nFunction/predicate with equivalent signature defined in "+cmp->loc().toString()); } } } } namespace { int matchIdx(std::vector& matched, Expression*& botarg, EnvI& env, const std::vector& v, const std::vector& args, bool strictEnums) { botarg = NULL; for (unsigned int i=0; i& fi_t = v[i].t; #ifdef MZN_DEBUG_FUNCTION_REGISTRY std::cerr << "try " << *v[i].fi; #endif if (fi_t.size() == args.size()) { bool match=true; for (unsigned int j=0; jtype(),fi_t[j],strictEnums)) { #ifdef MZN_DEBUG_FUNCTION_REGISTRY std::cerr << args[j]->type().toString(env) << " does not match " << fi_t[j].toString(env) << "\n"; #endif match=false; break; } if (args[j]->type().isbot() && fi_t[j].bt()!=Type::BT_TOP) { botarg = args[j]; } } if (match) { matched.push_back(v[i].fi); if (!botarg) { return i; } } } } return -1; } } FunctionI* Model::matchFn(EnvI& env, const ASTString& id, const std::vector& args, bool strictEnums) const { if (id==constants().var_redef->id()) return constants().var_redef; const Model* m = this; while (m->_parent) m = m->_parent; FnMap::const_iterator it = m->fnmap.find(id); if (it == m->fnmap.end()) { return NULL; } const std::vector& v = it->second; std::vector matched; Expression* botarg; (void) matchIdx(matched, botarg, env, v, args, strictEnums); if (matched.empty()) return NULL; if (matched.size()==1) return matched[0]; Type t = matched[0]->ti()->type(); t.ti(Type::TI_PAR); for (unsigned int i=1; iti()->type(),strictEnums)) throw TypeError(env, botarg->loc(), "ambiguous overloading on return type of function"); } return matched[0]; } FunctionI* Model::matchFn(EnvI& env, Call* c, bool strictEnums) const { if (c->id()==constants().var_redef->id()) return constants().var_redef; const Model* m = this; while (m->_parent) m = m->_parent; FnMap::const_iterator it = m->fnmap.find(c->id()); if (it == m->fnmap.end()) { return NULL; } const std::vector& v = it->second; std::vector matched; Expression* botarg = NULL; for (unsigned int i=0; i& fi_t = v[i].t; #ifdef MZN_DEBUG_FUNCTION_REGISTRY std::cerr << "try " << *v[i].fi; #endif if (fi_t.size() == c->n_args()) { bool match=true; for (unsigned int j=0; jn_args(); j++) { if (!env.isSubtype(c->arg(j)->type(),fi_t[j],strictEnums)) { #ifdef MZN_DEBUG_FUNCTION_REGISTRY std::cerr << c->arg(j)->type().toString(env) << " does not match " << fi_t[j].toString(env) << "\n"; std::cerr << "Wrong argument is " << *c->arg(j); #endif match=false; break; } if (c->arg(j)->type().isbot() && fi_t[j].bt()!=Type::BT_TOP) { botarg = c->arg(j); } } if (match) { if (botarg) matched.push_back(v[i].fi); else return v[i].fi; } } } if (matched.empty()) return NULL; if (matched.size()==1) return matched[0]; Type t = matched[0]->ti()->type(); t.ti(Type::TI_PAR); for (unsigned int i=1; iti()->type(),strictEnums)) throw TypeError(env, botarg->loc(), "ambiguous overloading on return type of function"); } return matched[0]; } namespace { int firstOverloaded(EnvI& env, const std::vector& v_f, int i_f) { int first_i_f=i_f; for (; first_i_f--; ) { // find first instance overloaded on subtypes if (v_f[first_i_f].t.size() != v_f[i_f].t.size()) { break; } bool allSubtypes = true; for (unsigned int i=0; i& args, FunctionI* f, FunctionI* g) const { const Model* m = this; while (m->_parent) m = m->_parent; FnMap::const_iterator it_f = m->fnmap.find(f->id()); FnMap::const_iterator it_g = m->fnmap.find(g->id()); assert(it_f != m->fnmap.end()); assert(it_g != m->fnmap.end()); const std::vector& v_f = it_f->second; const std::vector& v_g = it_g->second; std::vector dummyMatched; Expression* dummyBotarg; int i_f = matchIdx(dummyMatched, dummyBotarg, env, v_f, args, true); if (i_f == -1) return false; int i_g = matchIdx(dummyMatched, dummyBotarg, env, v_g, args, true); if (i_g == -1) return false; assert(i_f < v_f.size()); assert(i_g < v_g.size()); unsigned int first_i_f = firstOverloaded(env, v_f, i_f); unsigned int first_i_g = firstOverloaded(env, v_g, i_g); if (i_f-first_i_f != i_g-first_i_g) { // not the same number of overloaded versions return false; } for ( ; first_i_f <= i_f; first_i_f++, first_i_g++) { if (! (v_f[first_i_f].t == v_g[first_i_g].t) ) { // one of the overloaded versions does not agree in the types return false; } } return true; } FunctionI* Model::matchRevMap(EnvI& env, const Type& t0) const { const Model* m = this; while (m->_parent) m = m->_parent; Type t = t0; t.enumId(0); RevMapperMap::const_iterator it = revmapmap.find(t.toInt()); if (it != revmapmap.end()) { return it->second; } else { return NULL; } } Item*& Model::operator[] (int i) { assert(i < _items.size()); return _items[i]; } const Item* Model::operator[] (int i) const { assert(i < _items.size()); return _items[i]; } unsigned int Model::size(void) const { return static_cast(_items.size()); } std::vector::iterator Model::begin(void) { return _items.begin(); } std::vector::const_iterator Model::begin(void) const { return _items.begin(); } std::vector::iterator Model::end(void) { return _items.end(); } std::vector::const_iterator Model::end(void) const { return _items.end(); } void Model::compact(void) { struct { bool operator() (const Item* i) { return i->removed(); }} isremoved; _items.erase(remove_if(_items.begin(),_items.end(),isremoved), _items.end()); } } libminizinc-2.4.2/lib/optimize.cpp000066400000000000000000002042531360574160400171540ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include #include #include #include #include #include namespace MiniZinc { void VarOccurrences::add_idx(VarDeclI *i, int idx_i) { idx.insert(i->e()->id(), idx_i); } void VarOccurrences::add_idx(VarDecl *e, int idx_i) { assert(find(e) == -1); idx.insert(e->id(), idx_i); } int VarOccurrences::find(VarDecl* vd) { IdMap::iterator it = idx.find(vd->id()); return it==idx.end() ? -1 : it->second; } void VarOccurrences::remove(VarDecl *vd) { idx.remove(vd->id()); } void VarOccurrences::add(VarDecl* v, Item* i) { IdMap::iterator vi = _m.find(v->id()->decl()->id()); if (vi==_m.end()) { Items items; items.insert(i); _m.insert(v->id()->decl()->id(), items); } else { vi->second.insert(i); } } int VarOccurrences::remove(VarDecl* v, Item* i) { IdMap::iterator vi = _m.find(v->id()->decl()->id()); assert(vi!=_m.end()); vi->second.erase(i); return static_cast(vi->second.size()); } void VarOccurrences::removeAllOccurrences(VarDecl* v) { IdMap::iterator vi = _m.find(v->id()->decl()->id()); assert(vi!=_m.end()); vi->second.clear(); } void VarOccurrences::unify(EnvI& env, Model* m, Id* id0_0, Id *id1_0) { Id* id0 = id0_0->decl()->id(); Id* id1 = id1_0->decl()->id(); VarDecl* v0 = id0->decl(); VarDecl* v1 = id1->decl(); if (v0==v1) return; int v0idx = find(v0); assert(v0idx != -1); env.flat_removeItem(v0idx); IdMap::iterator vi0 = _m.find(v0->id()); if (vi0 != _m.end()) { IdMap::iterator vi1 = _m.find(v1->id()); if (vi1 == _m.end()) { _m.insert(v1->id(), vi0->second); } else { vi1->second.insert(vi0->second.begin(), vi0->second.end()); } _m.remove(v0->id()); } remove(v0); id0->redirect(id1); } void VarOccurrences::clear(void) { _m.clear(); idx.clear(); } int VarOccurrences::occurrences(VarDecl* v) { IdMap::iterator vi = _m.find(v->id()->decl()->id()); return (vi==_m.end() ? 0 : static_cast(vi->second.size())); } std::pair VarOccurrences::usages(VarDecl* v) { bool is_output = v->ann().contains(constants().ann.output_var) || v->ann().containsCall(constants().ann.output_array); auto vi = _m.find(v->id()->decl()->id()); if (vi == _m.end()) { return std::make_pair(0,is_output); } int count = 0; for (Item* i : vi->second) { auto vd = i->dyn_cast(); if (vd && vd->e() && vd->e()->e() && (vd->e()->e()->isa() || vd->e()->e()->isa())) { auto u = usages(vd->e()); is_output = is_output || u.second; count += u.first; } else { count++; } } return std::make_pair(count, is_output); } void CollectOccurrencesI::vVarDeclI(VarDeclI* v) { CollectOccurrencesE ce(vo,v); topDown(ce,v->e()); } void CollectOccurrencesI::vConstraintI(ConstraintI* ci) { CollectOccurrencesE ce(vo,ci); topDown(ce,ci->e()); for (ExpressionSetIter it = ci->e()->ann().begin(); it != ci->e()->ann().end(); ++it) topDown(ce, *it); } void CollectOccurrencesI::vSolveI(SolveI* si) { CollectOccurrencesE ce(vo,si); topDown(ce,si->e()); for (ExpressionSetIter it = si->ann().begin(); it != si->ann().end(); ++si) topDown(ce,*it); } bool isOutput(VarDecl* vd) { for (ExpressionSetIter it = vd->ann().begin(); it != vd->ann().end(); ++it) { if (*it) { if (*it==constants().ann.output_var) return true; if (Call* c = (*it)->dyn_cast()) { if (c->id() == constants().ann.output_array) return true; } } } return false; } void unify(EnvI& env, std::vector& deletedVarDecls, Id* id0, Id* id1) { if (id0->decl() != id1->decl()) { if (isOutput(id0->decl())) { std::swap(id0,id1); } if (id0->decl()->e() != NULL && !Expression::equal(id0->decl()->e(),id1->decl()->id())) { Expression* rhs = id0->decl()->e(); VarDeclI* vdi1 = (*env.flat())[env.vo.find(id1->decl())]->cast(); CollectOccurrencesE ce(env.vo, vdi1); topDown(ce, rhs); id1->decl()->e(rhs); id0->decl()->e(NULL); VarDeclI* vdi0 = (*env.flat())[env.vo.find(id0->decl())]->cast(); CollectDecls cd(env.vo, deletedVarDecls, vdi0); topDown(cd, rhs); } if (Expression::equal(id1->decl()->e(),id0->decl()->id())) { VarDeclI* vdi1 = (*env.flat())[env.vo.find(id1->decl())]->cast(); CollectDecls cd(env.vo, deletedVarDecls, vdi1); Expression* rhs = id1->decl()->e(); topDown(cd, rhs); id1->decl()->e(NULL); } // Compute intersection of domains if (id0->decl()->ti()->domain() != NULL) { if (id1->decl()->ti()->domain() != NULL) { if (id0->type().isint() || id0->type().isintset()) { IntSetVal* isv0 = eval_intset(env,id0->decl()->ti()->domain()); IntSetVal* isv1 = eval_intset(env,id1->decl()->ti()->domain()); IntSetRanges isv0r(isv0); IntSetRanges isv1r(isv1); Ranges::Inter inter(isv0r,isv1r); IntSetVal* nd = IntSetVal::ai(inter); if (nd->size()==0) { env.fail(); } else if (nd->card() != isv1->card()) { id1->decl()->ti()->domain(new SetLit(Location(), nd)); if (nd->card()==isv0->card()) { id1->decl()->ti()->setComputedDomain(id0->decl()->ti()->computedDomain()); } else { id1->decl()->ti()->setComputedDomain(false); } } } else if (id0->type().isbool()) { if (eval_bool(env,id0->decl()->ti()->domain()) != eval_bool(env,id1->decl()->ti()->domain())) { env.fail(); } } else { // float FloatSetVal* isv0 = eval_floatset(env,id0->decl()->ti()->domain()); FloatSetVal* isv1 = eval_floatset(env,id1->decl()->ti()->domain()); FloatSetRanges isv0r(isv0); FloatSetRanges isv1r(isv1); Ranges::Inter inter(isv0r,isv1r); FloatSetVal* nd = FloatSetVal::ai(inter); FloatSetRanges nd_r(nd); FloatSetRanges isv1r_2(isv1); if (nd->size()==0) { env.fail(); } else if (!Ranges::equal(nd_r,isv1r_2)) { id1->decl()->ti()->domain(new SetLit(Location(), nd)); FloatSetRanges nd_r_2(nd); FloatSetRanges isv0r_2(isv0); if (Ranges::equal(nd_r_2,isv0r_2)) { id1->decl()->ti()->setComputedDomain(id0->decl()->ti()->computedDomain()); } else { id1->decl()->ti()->setComputedDomain(false); } } } } else { id1->decl()->ti()->domain(id0->decl()->ti()->domain()); } } // If both variables are output variables, unify them in the output model if (isOutput(id0->decl())) { assert(env.output_vo_flat.find(id0->decl()) != -1); VarDecl* id0_output = (*env.output)[env.output_vo_flat.find(id0->decl())]->cast()->e(); assert(env.output_vo_flat.find(id1->decl()) != -1); VarDecl* id1_output = (*env.output)[env.output_vo_flat.find(id1->decl())]->cast()->e(); if (id0_output->e() == NULL) { id0_output->e(id1_output->id()); } } env.vo.unify(env, env.flat(), id0, id1); } } void substituteFixedVars(EnvI& env, Item* ii, std::vector& deletedVarDecls); void simplifyBoolConstraint(EnvI& env, Item* ii, VarDecl* vd, bool& remove, std::deque& vardeclQueue, std::deque& constraintQueue, std::vector& toRemove, std::vector& deletedVarDecls, std::unordered_map& nonFixedLiteralCount); bool simplifyConstraint(EnvI& env, Item* ii, std::vector& deletedVarDecls, std::deque& constraintQueue, std::deque& vardeclQueue); void pushVarDecl(EnvI& env, VarDeclI* vdi, int vd_idx, std::deque& q) { if (!vdi->removed() && !vdi->flag()) { vdi->flag(true); q.push_back(vd_idx); } } void pushVarDecl(EnvI& env, int vd_idx, std::deque& q) { pushVarDecl(env, (*env.flat())[vd_idx]->cast(), vd_idx, q); } void pushDependentConstraints(EnvI& env, Id* id, std::deque& q) { IdMap::iterator it = env.vo._m.find(id->decl()->id()); if (it != env.vo._m.end()) { for (VarOccurrences::Items::iterator item = it->second.begin(); item != it->second.end(); ++item) { if (ConstraintI* ci = (*item)->dyn_cast()) { if (!ci->removed() && !ci->flag()) { ci->flag(true); q.push_back(ci); } } else if (VarDeclI* vdi = (*item)->dyn_cast()) { if (vdi->e()->id()->decl() != vdi->e()) { vdi = (*env.flat())[env.vo.find(vdi->e()->id()->decl())]->cast(); } if (!vdi->removed() && !vdi->flag() && vdi->e()->e()) { vdi->flag(true); q.push_back(vdi); } } } } } void optimize(Env& env, bool chain_compression) { if (env.envi().failed()) return; try { EnvI& envi = env.envi(); Model& m = *envi.flat(); std::vector toAssignBoolVars; std::vector toRemoveConstraints; std::vector deletedVarDecls; // Queue of constraint and variable items that still need to be optimised std::deque constraintQueue; // Queue of variable declarations (indexes into the model) that still need to be optimised std::deque vardeclQueue; std::vector boolConstraints; GCLock lock; // Phase 0: clean up // - clear flags for all constraint and variable declaration items // (flags are used to indicate whether an item is already queued or not) for (unsigned int i=0; iremoved()) { if (ConstraintI* ci = m[i]->dyn_cast()) { ci->flag(false); } else if (VarDeclI* vdi = m[i]->dyn_cast()) { vdi->flag(false); } } } // Phase 1: initialise queues // - remove equality constraints between identifiers // - remove toplevel forall constraints // - collect exists, clauses and reified foralls in boolConstraints // - remove "constraint x" where x is a bool var // - unify variables that are assigned to an identifier // - push bool vars that are fixed and have a RHS (to propagate the RHS constraint) // - push int vars that are fixed (either have a RHS or a singleton domain) for (unsigned int i=0; iremoved()) continue; if (ConstraintI* ci = m[i]->dyn_cast()) { ci->flag(false); if (!ci->removed()) { if (Call* c = ci->e()->dyn_cast()) { if ( (c->id() == constants().ids.int_.eq || c->id() == constants().ids.bool_eq || c->id() == constants().ids.float_.eq || c->id() == constants().ids.set_eq) && c->arg(0)->isa() && c->arg(1)->isa() && (c->arg(0)->cast()->decl()->e()==NULL || c->arg(1)->cast()->decl()->e()==NULL) ) { // Equality constraint between two identifiers: unify unify(envi, deletedVarDecls, c->arg(0)->cast(), c->arg(1)->cast()); { VarDecl* vd = c->arg(0)->cast()->decl(); int v0idx = envi.vo.find(vd); pushVarDecl(envi, m[v0idx]->cast(), v0idx, vardeclQueue); } pushDependentConstraints(envi, c->arg(0)->cast(), constraintQueue); CollectDecls cd(envi.vo,deletedVarDecls,ci); topDown(cd,c); ci->e(constants().lit_true); envi.flat_removeItem(i); } else if ( c->id() == constants().ids.int_.lin_eq && Expression::equal(c->arg(2), IntLit::a(0))) { ArrayLit* al_c = follow_id(c->arg(0))->cast(); if (al_c->size()==2 && (*al_c)[0]->cast()->v() == -(*al_c)[1]->cast()->v()) { ArrayLit* al_x = follow_id(c->arg(1))->cast(); if ((*al_x)[0]->isa() && (*al_x)[1]->isa() && ((*al_x)[0]->cast()->decl()->e()==NULL || (*al_x)[1]->cast()->decl()->e()==NULL)) { // Equality constraint between two identifiers: unify unify(envi, deletedVarDecls, (*al_x)[0]->cast(), (*al_x)[1]->cast()); { VarDecl* vd = (*al_x)[0]->cast()->decl(); int v0idx = envi.vo.find(vd); pushVarDecl(envi, m[v0idx]->cast(), v0idx, vardeclQueue); } pushDependentConstraints(envi, (*al_x)[0]->cast(), constraintQueue); CollectDecls cd(envi.vo,deletedVarDecls,ci); topDown(cd,c); ci->e(constants().lit_true); envi.flat_removeItem(i); } } } else if (c->id()==constants().ids.forall) { // Remove forall constraints, assign variables inside the forall to true ArrayLit* al = follow_id(c->arg(0))->cast(); for (unsigned int j=al->size(); j--;) { if (Id* id = (*al)[j]->dyn_cast()) { if (id->decl()->ti()->domain()==NULL) { toAssignBoolVars.push_back(envi.vo.idx.find(id->decl()->id())->second); } else if (id->decl()->ti()->domain() == constants().lit_false) { env.envi().fail(); id->decl()->e(constants().lit_true); } } // todo: check else case (fixed bool inside a forall at this stage) } toRemoveConstraints.push_back(i); } else if (c->id()==constants().ids.exists || c->id()==constants().ids.clause) { // Add disjunctive constraints to the boolConstraints list boolConstraints.push_back(i); } } else if (Id* id = ci->e()->dyn_cast()) { if (id->decl()->ti()->domain() == constants().lit_false) { env.envi().fail(); ci->e(constants().lit_false); } else { if (id->decl()->ti()->domain()==NULL) { toAssignBoolVars.push_back(envi.vo.idx.find(id->decl()->id())->second); } toRemoveConstraints.push_back(i); } } } } else if (VarDeclI* vdi = m[i]->dyn_cast()) { vdi->flag(false); if (vdi->e()->e() && vdi->e()->e()->isa() && vdi->e()->type().dim()==0) { // unify variable with the identifier it's assigned to Id* id1 = vdi->e()->e()->cast(); vdi->e()->e(NULL); unify(envi, deletedVarDecls, vdi->e()->id(), id1); pushDependentConstraints(envi, id1, constraintQueue); } if (vdi->e()->type().isbool() && vdi->e()->type().dim()==0 && (vdi->e()->ti()->domain() == constants().lit_true || vdi->e()->ti()->domain() == constants().lit_false)) { // push RHS onto constraint queue since this bool var is fixed pushVarDecl(envi, vdi, i, vardeclQueue); pushDependentConstraints(envi, vdi->e()->id(), constraintQueue); } if (Call* c = Expression::dyn_cast(vdi->e()->e())) { if (c->id()==constants().ids.forall || c->id()==constants().ids.exists || c->id()==constants().ids.clause) { // push reified foralls, exists, clauses boolConstraints.push_back(i); } } if (vdi->e()->type().isint()) { if ((vdi->e()->e() && vdi->e()->e()->isa()) || (vdi->e()->ti()->domain() && vdi->e()->ti()->domain()->isa() && vdi->e()->ti()->domain()->cast()->isv()->size()==1 && vdi->e()->ti()->domain()->cast()->isv()->min()==vdi->e()->ti()->domain()->cast()->isv()->max())) { // Variable is assigned an integer, or has a singleton domain pushVarDecl(envi, vdi, i, vardeclQueue); pushDependentConstraints(envi, vdi->e()->id(), constraintQueue); } } } } // Phase 2: handle boolean constraints // - check if any boolean constraint is subsumed (e.g. a fixed false in a forall, or a fixed true in a disjunction) // - check if any boolean constraint has a single non-fixed literal left, then fix that literal for (unsigned int i=static_cast(boolConstraints.size()); i--;) { Item* bi = m[boolConstraints[i]]; if (bi->removed()) continue; Call* c; if (bi->isa()) { c = bi->cast()->e()->dyn_cast(); } else { c = bi->cast()->e()->e()->dyn_cast(); } if (c==NULL) continue; bool isConjunction = (c->id() == constants().ids.forall); bool subsumed = false; Id* finalId = NULL; bool finalIdNeg = false; int idCount = 0; std::vector pos; std::vector neg; for (unsigned int j=0; jn_args(); j++) { bool unit = (j==0 ? isConjunction : !isConjunction); ArrayLit* al = follow_id(c->arg(j))->cast(); for (unsigned int k=0; ksize(); k++) { if (Id* ident = (*al)[k]->dyn_cast()) { if (ident->decl()->ti()->domain() || (ident->decl()->e() && ident->decl()->e()->type().ispar()) ) { bool identValue = ident->decl()->ti()->domain() ? eval_bool(envi, ident->decl()->ti()->domain()) : eval_bool(envi, ident->decl()->e()); if (identValue != unit) { subsumed = true; goto subsumed_check_done; } } else { idCount++; finalId = ident; finalIdNeg = (j==1); if (j==0) pos.push_back(ident->decl()); else neg.push_back(ident->decl()); } } else { if ((*al)[k]->cast()->v()!=unit) { subsumed = true; goto subsumed_check_done; } } } } if (pos.size() > 0 && neg.size() > 0) { std::sort(pos.begin(),pos.end()); std::sort(neg.begin(), neg.end()); unsigned int ix=0; unsigned int iy=0; for (;;) { if (pos[ix]==neg[iy]) { subsumed = true; break; } if (pos[ix] < neg[iy]) { ix++; } else { iy++; } if (ix==pos.size() || iy==neg.size()) break; } } subsumed_check_done: if (subsumed) { if (isConjunction) { if (bi->isa()) { env.envi().fail(); } else { if (bi->cast()->e()->ti()->domain()) { if (eval_bool(envi, bi->cast()->e()->ti()->domain())) { envi.fail(); } } else { CollectDecls cd(envi.vo,deletedVarDecls,bi); topDown(cd,bi->cast()->e()->e()); bi->cast()->e()->ti()->domain(constants().lit_false); bi->cast()->e()->ti()->setComputedDomain(true); bi->cast()->e()->e(constants().lit_false); pushVarDecl(envi, bi->cast(), boolConstraints[i], vardeclQueue); pushDependentConstraints(envi, bi->cast()->e()->id(), constraintQueue); } } } else { if (bi->isa()) { CollectDecls cd(envi.vo,deletedVarDecls,bi); topDown(cd,bi->cast()->e()); env.envi().flat_removeItem(bi); } else { if (bi->cast()->e()->ti()->domain()) { if (!eval_bool(envi, bi->cast()->e()->ti()->domain())) { envi.fail(); } } else { CollectDecls cd(envi.vo,deletedVarDecls,bi); topDown(cd,bi->cast()->e()->e()); bi->cast()->e()->ti()->domain(constants().lit_true); bi->cast()->e()->ti()->setComputedDomain(true); bi->cast()->e()->e(constants().lit_true); pushVarDecl(envi, bi->cast(), boolConstraints[i], vardeclQueue); pushDependentConstraints(envi, bi->cast()->e()->id(), constraintQueue); } } } } else if (idCount==1 && bi->isa()) { assert(finalId->decl()->ti()->domain()==NULL); finalId->decl()->ti()->domain(constants().boollit(!finalIdNeg)); if (finalId->decl()->e()==NULL) finalId->decl()->e(constants().boollit(!finalIdNeg)); CollectDecls cd(envi.vo,deletedVarDecls,bi); topDown(cd,bi->cast()->e()); env.envi().flat_removeItem(bi); pushVarDecl(envi, envi.vo.idx.find(finalId->decl()->id())->second, vardeclQueue); pushDependentConstraints(envi, finalId, constraintQueue); } // todo: for var decls, we could unify the variable with the remaining finalId (the RHS) } // Fix all bool vars in toAssignBoolVars to true and push their declarations and constraints for (unsigned int i=static_cast(toAssignBoolVars.size()); i--;) { if (m[toAssignBoolVars[i]]->removed()) continue; VarDeclI* vdi = m[toAssignBoolVars[i]]->cast(); if (vdi->e()->ti()->domain()==NULL) { vdi->e()->ti()->domain(constants().lit_true); pushVarDecl(envi, vdi, toAssignBoolVars[i], vardeclQueue); pushDependentConstraints(envi, vdi->e()->id(), constraintQueue); } } // Phase 3: fixpoint of constraint and variable simplification std::unordered_map nonFixedLiteralCount; while (!vardeclQueue.empty() || !constraintQueue.empty()) { while (!vardeclQueue.empty()) { int var_idx = vardeclQueue.front(); vardeclQueue.pop_front(); m[var_idx]->cast()->flag(false); VarDecl* vd = m[var_idx]->cast()->e(); if (vd->type().isbool() && vd->ti()->domain()) { bool isTrue = vd->ti()->domain() == constants().lit_true; bool remove = false; if (vd->e()) { if (Id* id = vd->e()->dyn_cast()) { // Variable assigned to id, so fix id if (id->decl()->ti()->domain()==NULL) { id->decl()->ti()->domain(vd->ti()->domain()); pushVarDecl(envi, envi.vo.idx.find(id->decl()->id())->second, vardeclQueue); } else if (id->decl()->ti()->domain() != vd->ti()->domain()) { env.envi().fail(); } remove = true; } else if (Call* c = vd->e()->dyn_cast()) { if (isTrue && c->id()==constants().ids.forall) { // Reified forall is now fixed to true, so make all elements of the conjunction true remove = true; ArrayLit* al = follow_id(c->arg(0))->cast(); for (unsigned int i=0; isize(); i++) { if (Id* id = (*al)[i]->dyn_cast()) { if (id->decl()->ti()->domain()==NULL) { id->decl()->ti()->domain(constants().lit_true); pushVarDecl(envi, envi.vo.idx.find(id->decl()->id())->second, vardeclQueue); } else if (id->decl()->ti()->domain() == constants().lit_false) { env.envi().fail(); remove = true; } } } } else if (!isTrue && (c->id()==constants().ids.exists || c->id()==constants().ids.clause)) { // Reified disjunction is now fixed to false, so make all elements of the disjunction false remove = true; for (unsigned int i=0; in_args(); i++) { bool ispos = i==0; ArrayLit* al = follow_id(c->arg(i))->cast(); for (unsigned int j=0; jsize(); j++) { if (Id* id = (*al)[j]->dyn_cast()) { if (id->decl()->ti()->domain()==NULL) { id->decl()->ti()->domain(constants().boollit(!ispos)); pushVarDecl(envi, envi.vo.idx.find(id->decl()->id())->second, vardeclQueue); } else if (id->decl()->ti()->domain() == constants().boollit(ispos)) { env.envi().fail(); remove = true; } } } } } } } else { // If bool variable doesn't have a RHS, just remove it remove = true; } pushDependentConstraints(envi, vd->id(), constraintQueue); std::vector toRemove; IdMap::iterator it = envi.vo._m.find(vd->id()->decl()->id()); // Handle all boolean constraints that involve this variable if (it != envi.vo._m.end()) { for (VarOccurrences::Items::iterator item = it->second.begin(); item != it->second.end(); ++item) { if ((*item)->removed()) continue; if (VarDeclI* vdi = (*item)->dyn_cast()) { // The variable occurs in the RHS of another variable, so // if that is an array variable, simplify all constraints that // mention the array variable if (vdi->e()->e() && vdi->e()->e()->isa()) { IdMap::iterator ait = envi.vo._m.find(vdi->e()->id()->decl()->id()); if (ait != envi.vo._m.end()) { for (VarOccurrences::Items::iterator aitem = ait->second.begin(); aitem != ait->second.end(); ++aitem) { simplifyBoolConstraint(envi,*aitem,vd,remove,vardeclQueue,constraintQueue,toRemove,deletedVarDecls,nonFixedLiteralCount); } } continue; } } // Simplify the constraint *item (which depends on this variable) simplifyBoolConstraint(envi,*item,vd,remove,vardeclQueue,constraintQueue,toRemove,deletedVarDecls,nonFixedLiteralCount); } } // Actually remove all items that have become unnecessary in the step above for (unsigned int i=static_cast(toRemove.size()); i--;) { if (ConstraintI* ci = toRemove[i]->dyn_cast()) { CollectDecls cd(envi.vo,deletedVarDecls,ci); topDown(cd,ci->e()); envi.flat_removeItem(ci); } else { VarDeclI* vdi = toRemove[i]->cast(); CollectDecls cd(envi.vo,deletedVarDecls,vdi); topDown(cd,vdi->e()->e()); vdi->e()->e(NULL); } } if (remove) { deletedVarDecls.push_back(vd); } else { simplifyConstraint(envi,m[var_idx],deletedVarDecls,constraintQueue,vardeclQueue); } } else if (vd->type().isint() && vd->ti()->domain()) { IntSetVal* isv = eval_intset(envi, vd->ti()->domain()); if (isv->size()==1 && isv->card()==1) { simplifyConstraint(envi,m[var_idx],deletedVarDecls,constraintQueue,vardeclQueue); } } } // end of processing of variable queue // Now handle all non-boolean constraints (i.e. anything except forall, clause, exists) bool handledConstraint = false; while (!handledConstraint && !constraintQueue.empty()) { Item* item = constraintQueue.front(); constraintQueue.pop_front(); Call* c; ArrayLit* al = NULL; if (ConstraintI* ci = item->dyn_cast()) { ci->flag(false); c = Expression::dyn_cast(ci->e()); } else { if (item->removed()) { // This variable was removed because of unification, so we look up the // variable it was unified to item = m[envi.vo.find(item->cast()->e()->id()->decl())]->cast(); } item->cast()->flag(false); c = Expression::dyn_cast(item->cast()->e()->e()); al = Expression::dyn_cast(item->cast()->e()->e()); } if (!item->removed()) { if (al) { // Substitute all fixed variables by their values in array literals, then // push all constraints that depend on the array substituteFixedVars(envi, item, deletedVarDecls); pushDependentConstraints(envi, item->cast()->e()->id(), constraintQueue); } else if (!c || !(c->id()==constants().ids.forall || c->id()==constants().ids.exists || c->id()==constants().ids.clause) ) { // For any constraint that is not forall, exists or clause, // substitute fixed arguments, then simplify it substituteFixedVars(envi, item, deletedVarDecls); handledConstraint = simplifyConstraint(envi,item,deletedVarDecls,constraintQueue,vardeclQueue); } } } } // Clean up constraints that have been removed in the previous phase for (unsigned int i=static_cast(toRemoveConstraints.size()); i--;) { ConstraintI* ci = m[toRemoveConstraints[i]]->cast(); CollectDecls cd(envi.vo,deletedVarDecls,ci); topDown(cd,ci->e()); envi.flat_removeItem(toRemoveConstraints[i]); } // Phase 4: Chain Breaking if (chain_compression) { ImpCompressor imp(envi, m, deletedVarDecls, boolConstraints); LECompressor le(envi, m, deletedVarDecls); for (auto &item : m) { imp.trackItem(item); le.trackItem(item); } imp.compress(); le.compress(); } // Phase 5: handle boolean constraints again (todo: check if we can // refactor this into a separate function) // // Difference to phase 2: constraint argument arrays are actually shortened here if possible for (unsigned int i=static_cast(boolConstraints.size()); i--;) { Item* bi = m[boolConstraints[i]]; if (bi->removed()) continue; Call* c; std::vector removedVarDecls; if (bi->isa()) { c = bi->cast()->e()->dyn_cast(); } else { c = Expression::dyn_cast(bi->cast()->e()->e()); } if (c==NULL || !(c->id()==constants().ids.forall || c->id()==constants().ids.exists || c->id()==constants().ids.clause)) continue; bool isConjunction = (c->id() == constants().ids.forall); bool subsumed = false; for (unsigned int j=0; jn_args(); j++) { bool unit = (j==0 ? isConjunction : !isConjunction); ArrayLit* al = follow_id(c->arg(j))->cast(); std::vector compactedAl; for (unsigned int k=0; ksize(); k++) { if (Id* ident = (*al)[k]->dyn_cast()) { if (ident->decl()->ti()->domain()) { if (!(ident->decl()->ti()->domain()==constants().boollit(unit))) { subsumed = true; } removedVarDecls.push_back(ident->decl()); } else { compactedAl.push_back(ident); } } else { if ((*al)[k]->cast()->v()!=unit) { subsumed = true; } } } if (compactedAl.size() < al->size()) { c->arg(j, new ArrayLit(al->loc(), compactedAl)); c->arg(j)->type(Type::varbool(1)); } } if (subsumed) { if (isConjunction) { if (bi->isa()) { env.envi().fail(); } else { ArrayLit* al = follow_id(c->arg(0))->cast(); for (unsigned int j=0; jsize(); j++) { removedVarDecls.push_back((*al)[j]->cast()->decl()); } bi->cast()->e()->ti()->domain(constants().lit_false); bi->cast()->e()->ti()->setComputedDomain(true); bi->cast()->e()->e(constants().lit_false); } } else { if (bi->isa()) { CollectDecls cd(envi.vo,deletedVarDecls,bi); topDown(cd,bi->cast()->e()); env.envi().flat_removeItem(bi); } else { CollectDecls cd(envi.vo,deletedVarDecls,bi); topDown(cd,bi->cast()->e()->e()); bi->cast()->e()->ti()->domain(constants().lit_true); bi->cast()->e()->ti()->setComputedDomain(true); bi->cast()->e()->e(constants().lit_true); } } } for (unsigned int j=0; je()==NULL || removedVarDecls[j]->ti()->domain()==NULL || removedVarDecls[j]->ti()->computedDomain()) && !isOutput(removedVarDecls[j]) ) { deletedVarDecls.push_back(removedVarDecls[j]); } } } if (VarDeclI* vdi = bi->dyn_cast()) { if (envi.vo.occurrences(vdi->e())==0) { if ( (vdi->e()->e()==NULL || vdi->e()->ti()->domain()==NULL || vdi->e()->ti()->computedDomain()) && !isOutput(vdi->e()) ) { deletedVarDecls.push_back(vdi->e()); } } } } // Phase 6: remove deleted variables if possible while (!deletedVarDecls.empty()) { VarDecl* cur = deletedVarDecls.back(); deletedVarDecls.pop_back(); if (envi.vo.occurrences(cur) == 0) { IdMap::iterator cur_idx = envi.vo.idx.find(cur->id()); if (cur_idx != envi.vo.idx.end() && !m[cur_idx->second]->removed()) { if (isOutput(cur)) { // We have to change the output model if we remove this variable Expression* val = NULL; if (cur->type().isbool() && cur->ti()->domain()) { val = cur->ti()->domain(); } else if (cur->type().isint()) { if (cur->e() && cur->e()->isa()) { val = cur->e(); } else if (cur->ti()->domain() && cur->ti()->domain()->isa() && cur->ti()->domain()->cast()->isv()->size()==1 && cur->ti()->domain()->cast()->isv()->min()==cur->ti()->domain()->cast()->isv()->max()) { val = IntLit::a(cur->ti()->domain()->cast()->isv()->min()); } } if (val) { // Find corresponding variable in output model and fix it VarDecl* vd_out = (*envi.output)[envi.output_vo_flat.find(cur)]->cast()->e(); vd_out->e(val); CollectDecls cd(envi.vo,deletedVarDecls,m[cur_idx->second]->cast()); topDown(cd,cur->e()); envi.flat_removeItem(cur_idx->second); } } else { CollectDecls cd(envi.vo,deletedVarDecls,m[cur_idx->second]->cast()); topDown(cd,cur->e()); envi.flat_removeItem(cur_idx->second); } } } } } catch (ModelInconsistent&) { } } class SubstitutionVisitor : public EVisitor { protected: std::vector removed; Expression* subst(Expression* e) { if (VarDecl* vd = follow_id_to_decl(e)->dyn_cast()) { if (vd->type().isbool() && vd->ti()->domain()) { removed.push_back(vd); return vd->ti()->domain(); } if (vd->type().isint()) { if (vd->e() && vd->e()->isa()) { removed.push_back(vd); return vd->e(); } if (vd->ti()->domain() && vd->ti()->domain()->isa() && vd->ti()->domain()->cast()->isv()->size()==1 && vd->ti()->domain()->cast()->isv()->min()==vd->ti()->domain()->cast()->isv()->max()) { removed.push_back(vd); return IntLit::a(vd->ti()->domain()->cast()->isv()->min()); } } } return e; } public: /// Visit array literal void vArrayLit(ArrayLit& al) { for (unsigned int i=0; iisa(); } void remove(EnvI& env, Item* item, std::vector& deletedVarDecls) { for (unsigned int i=0; iann().remove(constants().ann.is_defined_var); if (env.vo.remove(removed[i], item) == 0) { if ( (removed[i]->e()==NULL || removed[i]->ti()->domain()==NULL || removed[i]->ti()->computedDomain()) && !isOutput(removed[i]) ) { deletedVarDecls.push_back(removed[i]); } } } } }; void substituteFixedVars(EnvI& env, Item* ii, std::vector& deletedVarDecls) { SubstitutionVisitor sv; if (ConstraintI* ci = ii->dyn_cast()) { topDown(sv, ci->e()); for (ExpressionSetIter it = ci->e()->ann().begin(); it != ci->e()->ann().end(); ++it) { topDown(sv, *it); } } else if (VarDeclI* vdi = ii->dyn_cast()) { topDown(sv, vdi->e()); for (ExpressionSetIter it = vdi->e()->ann().begin(); it != vdi->e()->ann().end(); ++it) { topDown(sv, *it); } } else { SolveI* si = ii->cast(); topDown(sv, si->e()); for (ExpressionSetIter it = si->ann().begin(); it != si->ann().end(); ++it) { topDown(sv, *it); } } sv.remove(env, ii, deletedVarDecls); } bool simplifyConstraint(EnvI& env, Item* ii, std::vector& deletedVarDecls, std::deque& constraintQueue, std::deque& vardeclQueue) { Expression* con_e; bool is_true; bool is_false; if (ConstraintI* ci = ii->dyn_cast()) { con_e = ci->e(); is_true = true; is_false = false; } else { VarDeclI* vdi = ii->cast(); con_e = vdi->e()->e(); is_true = (vdi->e()->type().isbool() && vdi->e()->ti()->domain()==constants().lit_true); is_false = (vdi->e()->type().isbool() && vdi->e()->ti()->domain()==constants().lit_false); assert(is_true || is_false || !vdi->e()->type().isbool() || vdi->e()->ti()->domain()==NULL); } if (Call* c = Expression::dyn_cast(con_e)) { if (c->id()==constants().ids.int_.eq || c->id()==constants().ids.bool_eq || c->id()==constants().ids.float_.eq) { if (is_true && c->arg(0)->isa() && c->arg(1)->isa() && (c->arg(0)->cast()->decl()->e()==NULL || c->arg(1)->cast()->decl()->e()==NULL) ) { unify(env, deletedVarDecls, c->arg(0)->cast(), c->arg(1)->cast()); pushDependentConstraints(env, c->arg(0)->cast(), constraintQueue); CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); env.flat_removeItem(ii); } else if (c->arg(0)->type().ispar() && c->arg(1)->type().ispar()) { Expression* e0 = eval_par(env,c->arg(0)); Expression* e1 = eval_par(env,c->arg(1)); bool is_equal = Expression::equal(e0, e1); if ((is_true && is_equal) || (is_false && !is_equal)) { // do nothing } else if ((is_true && !is_equal) || (is_false && is_equal)) { env.fail(); } else { VarDeclI* vdi = ii->cast(); CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); vdi->e()->e(constants().boollit(is_equal)); vdi->e()->ti()->domain(constants().boollit(is_equal)); vdi->e()->ti()->setComputedDomain(true); pushVarDecl(env, vdi, env.vo.find(vdi->e()), vardeclQueue); pushDependentConstraints(env, vdi->e()->id(), constraintQueue); } if (ii->isa()) { CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); env.flat_removeItem(ii); } } else if (is_true && ((c->arg(0)->isa() && c->arg(1)->type().ispar()) || (c->arg(1)->isa() && c->arg(0)->type().ispar())) ) { Id* ident = c->arg(0)->isa() ? c->arg(0)->cast() : c->arg(1)->cast(); Expression* arg = c->arg(0)->isa() ? c->arg(1) : c->arg(0); bool canRemove = false; TypeInst* ti = ident->decl()->ti(); switch (ident->type().bt()) { case Type::BT_BOOL: if (ti->domain() == NULL) { ti->domain(constants().boollit(eval_bool(env,arg))); ti->setComputedDomain(false); canRemove = true; } else { if (eval_bool(env,ti->domain())==eval_bool(env,arg)) { canRemove = true; } else { env.fail(); canRemove = true; } } break; case Type::BT_INT: { IntVal d = eval_int(env,arg); if (ti->domain() == NULL) { ti->domain(new SetLit(Location().introduce(), IntSetVal::a(d,d))); ti->setComputedDomain(false); canRemove = true; } else { IntSetVal* isv = eval_intset(env,ti->domain()); if (isv->contains(d)) { ident->decl()->ti()->domain(new SetLit(Location().introduce(), IntSetVal::a(d,d))); ident->decl()->ti()->setComputedDomain(false); canRemove = true; } else { env.fail(); canRemove = true; } } } break; case Type::BT_FLOAT: { if (ti->domain() == NULL) { ti->domain(new BinOp(Location().introduce(), arg, BOT_DOTDOT, arg)); ti->setComputedDomain(false); canRemove = true; } else { FloatVal value = eval_float(env,arg); if (LinearTraits::domain_contains(eval_floatset(env,ti->domain()), value)) { ti->domain(new BinOp(Location().introduce(), arg, BOT_DOTDOT, arg)); ti->setComputedDomain(false); canRemove = true; } else { env.fail(); canRemove = true; } } } break; default: break; } if (ident->decl()->e()==NULL) { ident->decl()->e(c->arg(0)->isa() ? c->arg(1) : c->arg(0)); ti->setComputedDomain(true); canRemove = true; } if (ident->decl()->e()->isa()) constraintQueue.push_back((*env.flat())[env.vo.find(ident->decl())]); pushDependentConstraints(env, ident, constraintQueue); if (canRemove) { CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); env.flat_removeItem(ii); } } } else if ((is_true || is_false) && c->id()==constants().ids.int_.le && ((c->arg(0)->isa() && c->arg(1)->type().ispar()) || (c->arg(1)->isa() && c->arg(0)->type().ispar())) ) { // todo: does this every happen? int_le shouldn't be generated any more Id* ident = c->arg(0)->isa() ? c->arg(0)->cast() : c->arg(1)->cast(); Expression* arg = c->arg(0)->isa() ? c->arg(1) : c->arg(0); IntSetVal* domain = ident->decl()->ti()->domain() ? eval_intset(env,ident->decl()->ti()->domain()) : NULL; if (domain) { BinOpType bot = c->arg(0)->isa() ? (is_true ? BOT_LQ : BOT_GR) : (is_true ? BOT_GQ: BOT_LE); IntSetVal* newDomain = LinearTraits::limit_domain(bot, domain, eval_int(env,arg)); ident->decl()->ti()->domain(new SetLit(Location().introduce(), newDomain)); ident->decl()->ti()->setComputedDomain(false); if (newDomain->min()==newDomain->max()) { pushDependentConstraints(env, ident, constraintQueue); } CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); if (VarDeclI* vdi = ii->dyn_cast()) { vdi->e()->e(constants().boollit(is_true)); pushDependentConstraints(env, vdi->e()->id(), constraintQueue); if (env.vo.occurrences(vdi->e())==0) { if (isOutput(vdi->e())) { VarDecl* vd_out = (*env.output)[env.output_vo_flat.find(vdi->e())]->cast()->e(); vd_out->e(constants().boollit(is_true)); } env.flat_removeItem(vdi); } } else { env.flat_removeItem(ii); } } } else if (c->id()==constants().ids.bool2int) { VarDeclI* vdi = ii->dyn_cast(); VarDecl* vd; bool fixed = false; bool b_val = false; if (vdi) { vd = vdi->e(); } else if (Id* ident = c->arg(1)->dyn_cast()) { vd = ident->decl(); } else { vd = NULL; } IntSetVal* vd_dom = NULL; if (vd) { if (vd->ti()->domain()) { vd_dom = eval_intset(env, vd->ti()->domain()); if (vd_dom->max()<0 || vd_dom->min()>1) { env.fail(); return true; } fixed = vd_dom->min()==vd_dom->max(); b_val = (vd_dom->min() == 1); } } else { fixed = true; b_val = (eval_int(env, c->arg(1))==1); } if (fixed) { if (c->arg(0)->type().ispar()) { bool b2i_val = eval_bool(env, c->arg(0)); if (b2i_val != b_val) { env.fail(); } else { CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); env.flat_removeItem(ii); } } else { Id* ident = c->arg(0)->cast(); TypeInst* ti = ident->decl()->ti(); if (ti->domain() == NULL) { ti->domain(constants().boollit(b_val)); ti->setComputedDomain(false); } else if (eval_bool(env,ti->domain())!=b_val) { env.fail(); } CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); if (vd) { vd->e(IntLit::a(b_val)); vd->ti()->setComputedDomain(true); } pushDependentConstraints(env, ident, constraintQueue); if (vdi) { if (env.vo.occurrences(vd)==0) { env.flat_removeItem(vdi); } } else { env.flat_removeItem(ii); } } } else { IntVal v = -1; if (BoolLit* bl = c->arg(0)->dyn_cast()) { v = bl->v() ? 1 : 0; } else if (Id* ident = c->arg(0)->dyn_cast()) { if (ident->decl()->ti()->domain()) { v = eval_bool(env,ident->decl()->ti()->domain()) ? 1 : 0; } } if (v != -1) { if (vd_dom && !vd_dom->contains(v)) { env.fail(); } else { CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); vd->e(IntLit::a(v)); vd->ti()->domain(new SetLit(Location().introduce(),IntSetVal::a(v, v))); vd->ti()->setComputedDomain(true); pushVarDecl(env, env.vo.find(vd), vardeclQueue); pushDependentConstraints(env, vd->id(), constraintQueue); } } } } else { // General propagation: call a propagator registered for this constraint type Expression* rewrite = NULL; GCLock lock; switch (OptimizeRegistry::registry().process(env, ii, c, rewrite)) { case OptimizeRegistry::CS_NONE: return false; case OptimizeRegistry::CS_OK: return true; case OptimizeRegistry::CS_FAILED: if (is_true) { env.fail(); return true; } else if (is_false) { if (ii->isa()) { CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); env.flat_removeItem(ii); } else { deletedVarDecls.push_back(ii->cast()->e()); } return true; } else { VarDeclI* vdi = ii->cast(); vdi->e()->ti()->domain(constants().lit_false); CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); vdi->e()->e(constants().lit_false); pushVarDecl(env, vdi, env.vo.find(vdi->e()), vardeclQueue); return true; } case OptimizeRegistry::CS_ENTAILED: if (is_true) { if (ii->isa()) { CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); env.flat_removeItem(ii); } else { deletedVarDecls.push_back(ii->cast()->e()); } return true; } else if (is_false) { env.fail(); return true; } else { VarDeclI* vdi = ii->cast(); vdi->e()->ti()->domain(constants().lit_true); CollectDecls cd(env.vo,deletedVarDecls,ii); topDown(cd,c); vdi->e()->e(constants().lit_true); pushVarDecl(env, vdi, env.vo.find(vdi->e()), vardeclQueue); return true; } case OptimizeRegistry::CS_REWRITE: { std::vector tdv; CollectDecls cd(env.vo,tdv,ii); topDown(cd,c); CollectOccurrencesE ce(env.vo,ii); topDown(ce,rewrite); for (unsigned int i=0; idyn_cast()) { ci->e(rewrite); constraintQueue.push_back(ii); } else { VarDeclI* vdi = ii->cast(); vdi->e()->e(rewrite); if (vdi->e()->e() && vdi->e()->e()->isa() && vdi->e()->type().dim()==0) { Id* id1 = vdi->e()->e()->cast(); vdi->e()->e(NULL); unify(env, deletedVarDecls, vdi->e()->id(), id1); pushDependentConstraints(env, id1, constraintQueue); } if (vdi->e()->e() && vdi->e()->e()->type().ispar() && vdi->e()->ti()->domain()) { if (vdi->e()->e()->type().isint()) { IntVal iv = eval_int(env, vdi->e()->e()); IntSetVal* dom = eval_intset(env, vdi->e()->ti()->domain()); if (!dom->contains(iv)) env.fail(); } else if (vdi->e()->e()->type().isintset()) { IntSetVal* isv = eval_intset(env, vdi->e()->e()); IntSetVal* dom = eval_intset(env, vdi->e()->ti()->domain()); IntSetRanges isv_r(isv); IntSetRanges dom_r(dom); if (!Ranges::subset(isv_r, dom_r)) env.fail(); } else if (vdi->e()->e()->type().isfloat()) { FloatVal fv = eval_float(env, vdi->e()->e()); FloatSetVal* dom = eval_floatset(env, vdi->e()->ti()->domain()); if (!dom->contains(fv)) env.fail(); } } if (vdi->e()->ti()->type()!=Type::varbool() || vdi->e()->ti()->domain()==NULL) pushVarDecl(env, vdi, env.vo.find(vdi->e()), vardeclQueue); if (is_true) { constraintQueue.push_back(ii); } } return true; } } } } return false; } int boolState(EnvI& env, Expression* e) { if (e->type().ispar()) { return eval_bool(env,e); } else { Id* id = e->cast(); if (id->decl()->ti()->domain()==NULL) return 2; return id->decl()->ti()->domain()==constants().lit_true; } } int decrementNonFixedVars(std::unordered_map& nonFixedLiteralCount, Call* c) { std::unordered_map::iterator it = nonFixedLiteralCount.find(c); if (it==nonFixedLiteralCount.end()) { int nonFixedVars = 0; for (unsigned int i=0; in_args(); i++) { ArrayLit* al = follow_id(c->arg(i))->cast(); nonFixedVars += al->size(); for (unsigned int j=al->size(); j--;) { if ((*al)[j]->type().ispar()) nonFixedVars--; } } nonFixedVars--; // for the identifier we're currently processing nonFixedLiteralCount.insert(std::make_pair(c, nonFixedVars)); return nonFixedVars; } else { it->second--; return it->second; } } void simplifyBoolConstraint(EnvI& env, Item* ii, VarDecl* vd, bool& remove, std::deque& vardeclQueue, std::deque& constraintQueue, std::vector& toRemove, std::vector& deletedVarDecls, std::unordered_map& nonFixedLiteralCount) { if (ii->isa()) { remove = false; return; } bool isTrue = vd->ti()->domain()==constants().lit_true; Expression* e = NULL; ConstraintI* ci = ii->dyn_cast(); VarDeclI* vdi = ii->dyn_cast(); if (ci) { e = ci->e(); } else if (vdi) { e = vdi->e()->e(); if (e==NULL) return; if (Id* id = e->dyn_cast()) { assert(id->decl()==vd); if (vdi->e()->ti()->domain()==NULL) { vdi->e()->ti()->domain(constants().boollit(isTrue)); vardeclQueue.push_back(env.vo.idx.find(vdi->e()->id())->second); } else if (id->decl()->ti()->domain() == constants().boollit(!isTrue)) { env.fail(); remove = false; } return; } } if (Id* ident = e->dyn_cast()) { assert(ident->decl() == vd); return; } if (e->isa()) { if (e == constants().lit_true && ci) { toRemove.push_back(ci); } return; } Call* c = e->cast(); if (c->id()==constants().ids.bool_eq) { Expression* b0 = c->arg(0); Expression* b1 = c->arg(1); int b0s = boolState(env,b0); int b1s = boolState(env,b1); if (b0s==2) { std::swap(b0,b1); std::swap(b0s,b1s); } assert(b0s!=2); if (ci || vdi->e()->ti()->domain()==constants().lit_true) { if (b0s != b1s) { if (b1s==2) { b1->cast()->decl()->ti()->domain(constants().boollit(isTrue)); vardeclQueue.push_back(env.vo.idx.find(b1->cast()->decl()->id())->second); if (ci) toRemove.push_back(ci); } else { env.fail(); remove = false; } } else { if (ci) toRemove.push_back(ci); } } else if (vdi && vdi->e()->ti()->domain()==constants().lit_false) { if (b0s != b1s) { if (b1s==2) { b1->cast()->decl()->ti()->domain(constants().boollit(isTrue)); vardeclQueue.push_back(env.vo.idx.find(b1->cast()->decl()->id())->second); } } else { env.fail(); remove = false; } } else { remove = false; } } else if (c->id()==constants().ids.forall || c->id()==constants().ids.exists || c->id()==constants().ids.clause) { if (isTrue && c->id()==constants().ids.exists) { if (ci) { toRemove.push_back(ci); } else { if (vdi->e()->ti()->domain()==NULL) { vdi->e()->ti()->domain(constants().lit_true); vardeclQueue.push_back(env.vo.idx.find(vdi->e()->id())->second); } else if (vdi->e()->ti()->domain()!=constants().lit_true) { env.fail(); vdi->e()->e(constants().lit_true); } } } else if (!isTrue && c->id()==constants().ids.forall) { if (ci) { env.fail(); toRemove.push_back(ci); } else { if (vdi->e()->ti()->domain()==NULL) { vdi->e()->ti()->domain(constants().lit_false); vardeclQueue.push_back(env.vo.idx.find(vdi->e()->id())->second); } else if (vdi->e()->ti()->domain()!=constants().lit_false) { env.fail(); vdi->e()->e(constants().lit_false); } } } else { int nonfixed = decrementNonFixedVars(nonFixedLiteralCount,c); bool isConjunction = (c->id() == constants().ids.forall); assert(nonfixed >=0); if (nonfixed<=1) { bool subsumed = false; int nonfixed_i=-1; int nonfixed_j=-1; int realNonFixed = 0; for (unsigned int i=0; in_args(); i++) { bool unit = (i==0 ? isConjunction : !isConjunction); ArrayLit* al = follow_id(c->arg(i))->cast(); realNonFixed += al->size(); for (unsigned int j=al->size(); j--;) { if ((*al)[j]->type().ispar() || (*al)[j]->cast()->decl()->ti()->domain()) realNonFixed--; if ((*al)[j]->type().ispar() && eval_bool(env,(*al)[j]) != unit) { subsumed = true; i=2; // break out of outer loop break; } else if (Id* id = (*al)[j]->dyn_cast()) { if (id->decl()->ti()->domain()) { bool idv = (id->decl()->ti()->domain()==constants().lit_true); if (unit != idv) { subsumed = true; i=2; // break out of outer loop break; } } else { nonfixed_i = i; nonfixed_j = j; } } } } if (subsumed) { if (ci) { if (isConjunction) { env.fail(); ci->e(constants().lit_false); } else { toRemove.push_back(ci); } } else { if (vdi->e()->ti()->domain()==NULL) { vdi->e()->ti()->domain(constants().boollit(!isConjunction)); vardeclQueue.push_back(env.vo.idx.find(vdi->e()->id())->second); } else if (vdi->e()->ti()->domain()!=constants().boollit(!isConjunction)) { env.fail(); vdi->e()->e(constants().boollit(!isConjunction)); } } } else if (realNonFixed==0) { if (ci) { if (isConjunction) { toRemove.push_back(ci); } else { env.fail(); ci->e(constants().lit_false); } } else { if (vdi->e()->ti()->domain()==NULL) { vdi->e()->ti()->domain(constants().boollit(isConjunction)); vardeclQueue.push_back(env.vo.idx.find(vdi->e()->id())->second); } else if (vdi->e()->ti()->domain()!=constants().boollit(isConjunction)) { env.fail(); vdi->e()->e(constants().boollit(isConjunction)); } toRemove.push_back(vdi); } } else { // not subsumed, nonfixed==1 assert(nonfixed_i != -1); ArrayLit* al = follow_id(c->arg(nonfixed_i))->cast(); Id* ident = (*al)[nonfixed_j]->cast(); if (ci || vdi->e()->ti()->domain()) { bool result = nonfixed_i==0; if (vdi && vdi->e()->ti()->domain()==constants().lit_false) result = !result; VarDecl* vd = ident->decl(); if (vd->ti()->domain()==NULL) { vd->ti()->domain(constants().boollit(result)); vardeclQueue.push_back(env.vo.idx.find(vd->id())->second); } else if (vd->ti()->domain()!=constants().boollit(result)) { env.fail(); vd->e(constants().lit_true); } } else { if (nonfixed_i==0) { // this is a clause, exists or forall with a single non-fixed variable, // assigned to a non-fixed variable => turn into simple equality vdi->e()->e(NULL); unify(env, deletedVarDecls, vdi->e()->id(), ident); pushDependentConstraints(env, ident, constraintQueue); } else { remove = false; } } } } else if (c->id()==constants().ids.clause) { int posOrNeg = isTrue ? 0 : 1; ArrayLit* al = follow_id(c->arg(posOrNeg))->cast(); ArrayLit* al_other = follow_id(c->arg(1-posOrNeg))->cast(); if (ci && al->size()==1 && (*al)[0]!=vd->id() && al_other->size()==1) { // simple implication assert((*al_other)[0]==vd->id()); if (ci) { if ((*al)[0]->type().ispar()) { if (eval_bool(env,(*al)[0])==isTrue) { toRemove.push_back(ci); } else { env.fail(); remove = false; } } else { Id* id = (*al)[0]->cast(); if (id->decl()->ti()->domain()==NULL) { id->decl()->ti()->domain(constants().boollit(isTrue)); vardeclQueue.push_back(env.vo.idx.find(id->decl()->id())->second); } else { if (id->decl()->ti()->domain()==constants().boollit(isTrue)) { toRemove.push_back(ci); } else { env.fail(); remove = false; } } } } } else { // proper clause for (unsigned int i=0; isize(); i++) { if ((*al)[i]==vd->id()) { if (ci) { toRemove.push_back(ci); } else { if (vdi->e()->ti()->domain()==NULL) { vdi->e()->ti()->domain(constants().lit_true); vardeclQueue.push_back(env.vo.idx.find(vdi->e()->id())->second); } else if (vdi->e()->ti()->domain()!=constants().lit_true) { env.fail(); vdi->e()->e(constants().lit_true); } } break; } } } } } } else { remove = false; } } } libminizinc-2.4.2/lib/optimize_constraints.cpp000066400000000000000000000414731360574160400216060ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include namespace MiniZinc { void OptimizeRegistry::reg(const MiniZinc::ASTString& call, optimizer opt) { _m.insert(std::make_pair(call, opt)); } OptimizeRegistry::ConstraintStatus OptimizeRegistry::process(EnvI& env, MiniZinc::Item* i, MiniZinc::Call* c, Expression*& rewrite) { ASTStringMap::t::iterator it = _m.find(c->id()); if (it != _m.end()) { return it->second(env,i,c,rewrite); } return CS_NONE; } OptimizeRegistry& OptimizeRegistry::registry(void) { static OptimizeRegistry reg; return reg; } namespace Optimizers { OptimizeRegistry::ConstraintStatus o_linear(EnvI& env, Item* ii, Call* c, Expression*& rewrite) { ArrayLit* al_c = eval_array_lit(env,c->arg(0)); std::vector coeffs(al_c->size()); for (unsigned int i=0; isize(); i++) { coeffs[i] = eval_int(env,(*al_c)[i]); } ArrayLit* al_x = eval_array_lit(env,c->arg(1)); std::vector x(al_x->size()); for (unsigned int i=0; isize(); i++) { x[i] = (*al_x)[i]; } IntVal d = 0; simplify_lin(coeffs, x, d); if (coeffs.size()==0) { bool failed; if (c->id()==constants().ids.int_.lin_le) { failed = (d > eval_int(env,c->arg(2))); } else if (c->id()==constants().ids.int_.lin_eq) { failed = (d != eval_int(env,c->arg(2))); } else { failed = (d == eval_int(env,c->arg(2))); } if (failed) { return OptimizeRegistry::CS_FAILED; } else { return OptimizeRegistry::CS_ENTAILED; } } else if (coeffs.size()==1 && (ii->isa() || ii->cast()->e()->ti()->domain()==constants().lit_true)) { VarDecl* vd = x[0]()->cast()->decl(); IntSetVal* domain = vd->ti()->domain() ? eval_intset(env,vd->ti()->domain()) : NULL; if (c->id()==constants().ids.int_.lin_eq) { IntVal rd = eval_int(env,c->arg(2))-d; if (rd % coeffs[0] == 0) { IntVal nd = rd / coeffs[0]; if (domain && !domain->contains(nd)) return OptimizeRegistry::CS_FAILED; std::vector args(2); args[0] = x[0](); args[1] = IntLit::a(nd); Call* c = new Call(Location(), constants().ids.int_.eq, args); c->type(Type::varbool()); rewrite = c; return OptimizeRegistry::CS_REWRITE; } else { return OptimizeRegistry::CS_FAILED; } } else if (c->id()==constants().ids.int_.lin_le) { IntVal ac = std::abs(coeffs[0]); IntVal rd = eval_int(env,c->arg(2))-d; IntVal ad = std::abs(rd); IntVal nd; if (ad % ac == 0) { nd = rd / coeffs[0]; } else { double nd_d = static_cast(ad.toInt()) / static_cast(ac.toInt()); if (coeffs[0] >= 0 && rd >= 0) { nd = static_cast(std::floor(nd_d)); } else if (rd >= 0) { nd = -static_cast(std::floor(nd_d)); } else if (coeffs[0] >= 0) { nd = -static_cast(std::ceil(nd_d)); } else { nd = static_cast(std::ceil(nd_d)); } } bool swapSign = coeffs[0] < 0; if (domain) { if (swapSign) { if (domain->max() < nd) { return OptimizeRegistry::CS_FAILED; } else if (domain->min() >= nd) return OptimizeRegistry::CS_ENTAILED; } else { if (domain->min() > nd) { return OptimizeRegistry::CS_FAILED; } else if (domain->max() <= nd) return OptimizeRegistry::CS_ENTAILED; } std::vector args(2); args[0] = x[0](); args[1] = IntLit::a(nd); if (swapSign) std::swap(args[0], args[1]); Call* nc = new Call(Location(), constants().ids.int_.le, args); nc->type(Type::varbool()); rewrite = nc; return OptimizeRegistry::CS_REWRITE; } } } else if (c->id()==constants().ids.int_.lin_eq && coeffs.size()==2 && ((coeffs[0]==1 && coeffs[1]==-1) || (coeffs[1]==1 && coeffs[0]==-1)) && eval_int(env,c->arg(2))-d==0) { std::vector args(2); args[0] = x[0](); args[1] = x[1](); Call* c = new Call(Location(), constants().ids.int_.eq, args); rewrite = c; return OptimizeRegistry::CS_REWRITE; } if (coeffs.size() < al_c->size()) { std::vector coeffs_e(coeffs.size()); std::vector x_e(coeffs.size()); for (unsigned int i=0; iloc(),coeffs_e); al_c_new->type(Type::parint(1)); ArrayLit* al_x_new = new ArrayLit(al_x->loc(),x_e); al_x_new->type(al_x->type()); std::vector args(3); args[0] = al_c_new; args[1] = al_x_new; args[2] = IntLit::a(eval_int(env,c->arg(2))-d); Call* nc = new Call(Location(), c->id(), args); nc->type(Type::varbool()); for (ExpressionSetIter it = c->ann().begin(); it != c->ann().end(); ++it) { nc->addAnnotation(*it); } rewrite = nc; return OptimizeRegistry::CS_REWRITE; } return OptimizeRegistry::CS_OK; } OptimizeRegistry::ConstraintStatus o_lin_exp(EnvI& env, Item* i, Call* c, Expression*& rewrite) { if (c->type().isint()) { ArrayLit* al_c = eval_array_lit(env,c->arg(0)); std::vector coeffs(al_c->size()); for (unsigned int i=0; isize(); i++) { coeffs[i] = eval_int(env,(*al_c)[i]); } ArrayLit* al_x = eval_array_lit(env,c->arg(1)); std::vector x(al_x->size()); for (unsigned int i=0; isize(); i++) { x[i] = (*al_x)[i]; } IntVal d = eval_int(env,c->arg(2)); simplify_lin(coeffs, x, d); if (coeffs.size()==0) { rewrite = IntLit::a(d); return OptimizeRegistry::CS_REWRITE; } else if (coeffs.size() < al_c->size()) { if (coeffs.size()==1 && coeffs[0]==1 && d==0) { rewrite = x[0](); return OptimizeRegistry::CS_REWRITE; } std::vector coeffs_e(coeffs.size()); std::vector x_e(coeffs.size()); for (unsigned int i=0; iloc(),coeffs_e); al_c_new->type(Type::parint(1)); ArrayLit* al_x_new = new ArrayLit(al_x->loc(),x_e); al_x_new->type(al_x->type()); std::vector args(3); args[0] = al_c_new; args[1] = al_x_new; args[2] = IntLit::a(d); Call* nc = new Call(Location(),c->id(),args); nc->type(c->type()); for (ExpressionSetIter it = c->ann().begin(); it != c->ann().end(); ++it) { nc->addAnnotation(*it); } rewrite = nc; return OptimizeRegistry::CS_REWRITE; } } return OptimizeRegistry::CS_OK; } OptimizeRegistry::ConstraintStatus o_element(EnvI& env, Item* i, Call* c, Expression*& rewrite) { if (c->arg(0)->isa()) { IntVal idx = eval_int(env,c->arg(0)); ArrayLit* al = eval_array_lit(env,c->arg(1)); if (idx < 1 || idx > al->size()) { return OptimizeRegistry::CS_FAILED; } Expression* result = (*al)[static_cast(idx.toInt())-1]; std::vector args(2); args[0] = result; args[1] = c->arg(2); Call* eq = new Call(Location(),constants().ids.int_.eq,args); rewrite = eq; return OptimizeRegistry::CS_REWRITE; } return OptimizeRegistry::CS_OK; } OptimizeRegistry::ConstraintStatus o_clause(EnvI& env, Item* i, Call* c, Expression*& rewrite) { std::vector pos; std::vector neg; ArrayLit* al_pos = eval_array_lit(env, c->arg(0)); for (unsigned int i=0; isize(); i++) { if (Id* ident = (*al_pos)[i]->dyn_cast()) { if (ident->decl()->ti()->domain()==NULL) pos.push_back(ident->decl()); } } ArrayLit* al_neg = eval_array_lit(env, c->arg(1)); for (unsigned int i=0; isize(); i++) { if (Id* ident = (*al_neg)[i]->dyn_cast()) { if (ident->decl()->ti()->domain()==NULL) neg.push_back(ident->decl()); } } bool subsumed = false; if (pos.size() > 0 && neg.size() > 0) { std::sort(pos.begin(),pos.end()); std::sort(neg.begin(), neg.end()); unsigned int ix=0; unsigned int iy=0; for (;;) { if (pos[ix]==neg[iy]) { subsumed = true; break; } if (pos[ix] < neg[iy]) { ix++; } else { iy++; } if (ix==pos.size() || iy==neg.size()) break; } } if (subsumed) { return OptimizeRegistry::CS_ENTAILED; } else { return OptimizeRegistry::CS_OK; } } OptimizeRegistry::ConstraintStatus o_div(EnvI& env, Item* i, Call* c, Expression*& rewrite) { if (c->arg(1)->type().ispar()) { IntVal c1v = eval_int(env, c->arg(1)); if (c->arg(0)->type().ispar() && c->n_args()==3 && c->arg(2)->type().ispar()) { IntVal c0v = eval_int(env, c->arg(0)); IntVal c2v = eval_int(env, c->arg(2)); return (c0v / c1v == c2v) ? OptimizeRegistry::CS_ENTAILED : OptimizeRegistry::CS_FAILED; } } return OptimizeRegistry::CS_OK; } OptimizeRegistry::ConstraintStatus o_times(EnvI& env, Item* i, Call* c, Expression*& rewrite) { Expression* result = nullptr; Expression* arg0 = c->arg(0); Expression* arg1 = c->arg(1); if (arg0->type().ispar() && arg1->type().ispar()) { IntVal c0v = eval_int(env, arg0); IntVal c1v = eval_int(env, arg1); result = IntLit::a(c0v*c1v); } else if (arg0->type().ispar()) { IntVal c0v = eval_int(env, arg0); if (c0v==0) { result = IntLit::a(0); } else if (c0v==1) { result = arg1; } } else if (arg1->type().ispar()) { IntVal c1v = eval_int(env, arg1); if (c1v==0) { result = IntLit::a(0); } if (c1v==1) { result = arg0; } } if (result) { if (c->n_args()==2) { // this is the functional version of times rewrite = result; return OptimizeRegistry::CS_REWRITE; } else { // this is the relational version of times assert(c->n_args()==3); rewrite = new Call(Location().introduce(), constants().ids.int_.eq, {c->arg(2),result}); return OptimizeRegistry::CS_REWRITE; } } return OptimizeRegistry::CS_OK; } OptimizeRegistry::ConstraintStatus o_set_in(EnvI& env, Item* i, Call* c, Expression*& rewrite) { if (c->arg(1)->type().ispar()) { if (c->arg(0)->type().ispar()) { IntSetVal* isv = eval_intset(env, c->arg(1)); return isv->contains(eval_int(env,c->arg(0))) ? OptimizeRegistry::CS_ENTAILED : OptimizeRegistry::CS_FAILED; } else if (Id* ident = c->arg(0)->dyn_cast()) { VarDecl* vd = ident->decl(); IntSetVal* isv = eval_intset(env, c->arg(1)); if (vd->ti()->domain()) { IntSetVal* dom = eval_intset(env, vd->ti()->domain()); { IntSetRanges isv_r(isv); IntSetRanges dom_r(dom); if (Ranges::subset(dom_r, isv_r)) return OptimizeRegistry::CS_ENTAILED; } { IntSetRanges isv_r(isv); IntSetRanges dom_r(dom); if (Ranges::disjoint(dom_r, isv_r)) return OptimizeRegistry::CS_FAILED; } } else if (isv->min()==isv->max()) { std::vector args(2); args[0] = vd->id(); args[1] = IntLit::a(isv->min()); Call* eq = new Call(Location(),constants().ids.int_.eq,args); rewrite = eq; return OptimizeRegistry::CS_REWRITE; } } } return OptimizeRegistry::CS_OK; } OptimizeRegistry::ConstraintStatus o_int_ne(EnvI& env, Item* i, Call* c, Expression*& rewrite) { Expression* e0 = c->arg(0); Expression* e1 = c->arg(1); if (e0->type().ispar() && e1->type().ispar()) { return eval_int(env, e0) != eval_int(env, e1) ? OptimizeRegistry::CS_ENTAILED : OptimizeRegistry::CS_FAILED; } if (e1->isa()) { std::swap(e0, e1); } if (Id* ident = e0->dyn_cast()) { if (e1->type().ispar()) { if (ident->decl()->ti()->domain()) { IntVal e1v = eval_int(env, e1); IntSetVal* isv = eval_intset(env, ident->decl()->ti()->domain()); if (!isv->contains(e1v)) return OptimizeRegistry::CS_ENTAILED; if (e1v==isv->min() && e1v==isv->max()) return OptimizeRegistry::CS_FAILED; } } } return OptimizeRegistry::CS_OK; } OptimizeRegistry::ConstraintStatus o_int_le(EnvI& env, Item* i, Call* c, Expression*& rewrite) { Expression* e0 = c->arg(0); Expression* e1 = c->arg(1); if (e0->type().ispar() && e1->type().ispar()) { return eval_int(env, e0) <= eval_int(env, e1) ? OptimizeRegistry::CS_ENTAILED : OptimizeRegistry::CS_FAILED; } bool swapped = false; if (e1->isa()) { std::swap(e0, e1); swapped = true; } if (Id* ident = e0->dyn_cast()) { if (e1->type().ispar()) { if (ident->decl()->ti()->domain()) { IntVal e1v = eval_int(env, e1); IntSetVal* isv = eval_intset(env, ident->decl()->ti()->domain()); if (!swapped) { if (isv->max() <= e1v) return OptimizeRegistry::CS_ENTAILED; if (isv->min() > e1v) return OptimizeRegistry::CS_FAILED; } else { if (e1v <= isv->min()) return OptimizeRegistry::CS_ENTAILED; if (e1v > isv->max()) return OptimizeRegistry::CS_FAILED; } } } } return OptimizeRegistry::CS_OK; } class Register { private: Model* _keepAliveModel; public: Register(void) { GCLock lock; _keepAliveModel = new Model; ASTString id_element("array_int_element"); ASTString id_var_element("array_var_int_element"); std::vector e; e.push_back(new StringLit(Location(),id_element)); e.push_back(new StringLit(Location(),id_var_element)); _keepAliveModel->addItem(new ConstraintI(Location(),new ArrayLit(Location(),e))); OptimizeRegistry::registry().reg(constants().ids.int_.lin_eq, o_linear); OptimizeRegistry::registry().reg(constants().ids.int_.lin_le, o_linear); OptimizeRegistry::registry().reg(constants().ids.int_.lin_ne, o_linear); OptimizeRegistry::registry().reg(constants().ids.int_.div, o_div); OptimizeRegistry::registry().reg(constants().ids.int_.times, o_times); OptimizeRegistry::registry().reg(id_element, o_element); OptimizeRegistry::registry().reg(constants().ids.lin_exp, o_lin_exp); OptimizeRegistry::registry().reg(id_var_element, o_element); OptimizeRegistry::registry().reg(constants().ids.clause, o_clause); OptimizeRegistry::registry().reg(constants().ids.bool_clause, o_clause); OptimizeRegistry::registry().reg(constants().ids.set_in, o_set_in); OptimizeRegistry::registry().reg(constants().ids.int_.ne, o_int_ne); OptimizeRegistry::registry().reg(constants().ids.int_.le, o_int_le); } ~Register(void) { delete _keepAliveModel; } } _r; } } libminizinc-2.4.2/lib/options.cpp000066400000000000000000000126021360574160400170020ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offOptions::set: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include namespace MiniZinc { Expression* Options::getParam(const std::string& name) const { std::unordered_map::const_iterator it = _options.find(name); if(it == _options.end()) { std::stringstream ss; ss << "Could not find option: \"" << name << "\"." << std::endl; throw InternalError(ss.str()); } return (it->second)(); } void Options::setIntParam(const std::string& name, KeepAlive ka) { Expression* e = ka(); if(e && e->type().ispar() && e->type().isint()) { _options[name] = ka; } else { std::stringstream ss; ss << "For option: " << name << " expected Par Int, received " << e->type().nonEnumToString() << std::endl; throw InternalError(ss.str()); } } void Options::setFloatParam(const std::string& name, KeepAlive ka) { Expression* e = ka(); if(e && e->type().ispar() && e->type().isfloat()) { _options[name] = ka; } else { std::stringstream ss; ss << "For option: " << name << " expected Par Float, received " << e->type().nonEnumToString() << std::endl; throw InternalError(ss.str()); } } void Options::setBoolParam(const std::string& name, KeepAlive ka) { Expression* e = ka(); if(e && e->type().ispar() && e->type().isbool()) { _options[name] = ka; } else { std::stringstream ss; ss << "For option: " << name << " expected Par Bool, received " << e->type().nonEnumToString() << std::endl; throw InternalError(ss.str()); } } void Options::setStringParam(const std::string& name, KeepAlive ka) { Expression* e = ka(); if(e && e->type().ispar() && e->type().isstring()) { _options[name] = ka; } else { std::stringstream ss; ss << "For option: " << name << " expected Par String, received " << e->type().nonEnumToString() << std::endl; throw InternalError(ss.str()); } } void Options::setIntParam(const std::string& name, long long int e) { GCLock lock; IntLit* il = IntLit::a(e); KeepAlive ka(il); setIntParam(name, ka); }; void Options::setFloatParam(const std::string& name, double e) { GCLock lock; FloatLit* fl = FloatLit::a(e); KeepAlive ka(fl); setFloatParam(name, ka); } void Options::setBoolParam(const std::string& name, bool e) { KeepAlive ka(constants().boollit(e)); setBoolParam(name, ka); } void Options::setStringParam(const std::string& name, std::string e) { GCLock lock; StringLit* sl = new StringLit(Location(), e); KeepAlive ka(sl); setStringParam(name, ka); } long long int Options::getIntParam(const std::string& name) const { if(IntLit* il = getParam(name)->dyn_cast()) { return il->v().toInt(); } else { std::stringstream ss; ss << "Option: \"" << name << "\" is not Par Int" << std::endl; throw InternalError(ss.str()); } } long long int Options::getIntParam(const std::string& name, long long int def) const { if (hasParam(name)) { if(IntLit* il = getParam(name)->dyn_cast()) { return il->v().toInt(); } } return def; } double Options::getFloatParam(const std::string& name) const { if(FloatLit* fl = getParam(name)->dyn_cast()) { return fl->v().toDouble(); } else { std::stringstream ss; ss << "Option: \"" << name << "\" is not Par Float" << std::endl; throw InternalError(ss.str()); } } double Options::getFloatParam(const std::string& name, double def) const { if (hasParam(name)) { if(FloatLit* fl = getParam(name)->dyn_cast()) { return fl->v().toDouble(); } } return def; } bool Options::getBoolParam(const std::string& name) const { if(BoolLit* bl = getParam(name)->dyn_cast()) { return bl->v(); } else { std::stringstream ss; ss << "Option: \"" << name << "\" is not Par Bool" << std::endl; throw InternalError(ss.str()); } } bool Options::getBoolParam(const std::string& name, bool def) const { if (hasParam(name)) { if(BoolLit* bl = getParam(name)->dyn_cast()) { return bl->v(); } } return def; } std::string Options::getStringParam(const std::string& name) const { if(StringLit* sl = getParam(name)->dyn_cast()) { return sl->v().str(); } else { std::stringstream ss; ss << "Option: \"" << name << "\" is not Par String" << std::endl; throw InternalError(ss.str()); } } std::string Options::getStringParam(const std::string& name, std::string def) const { if (hasParam(name)) { if(StringLit* sl = getParam(name)->dyn_cast()) { return sl->v().str(); } } return def; } bool Options::hasParam(const std::string& name) const { return _options.find(name) != _options.end(); } std::ostream& Options::dump(std::ostream& os) { for ( auto& it: _options ) os << it.first << ':' << it.second() << ' '; return os; } } libminizinc-2.4.2/lib/output.cpp000066400000000000000000001305721360574160400166560ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include namespace MiniZinc { void outputVarDecls(EnvI& env, Item* ci, Expression* e); bool cannotUseRHSForOutput(EnvI& env, Expression* e, std::unordered_set& seen_functions) { if (e==NULL) return true; class V : public EVisitor { public: EnvI& env; std::unordered_set& seen_functions; bool success; V(EnvI& env0, std::unordered_set& seen_functions0) : env(env0), seen_functions(seen_functions0), success(true) {} /// Visit anonymous variable void vAnonVar(const AnonVar&) { success = false; } /// Visit array literal void vArrayLit(const ArrayLit&) {} /// Visit array access void vArrayAccess(const ArrayAccess&) {} /// Visit array comprehension void vComprehension(const Comprehension&) {} /// Visit if-then-else void vITE(const ITE&) {} /// Visit binary operator void vBinOp(const BinOp&) {} /// Visit unary operator void vUnOp(const UnOp&) {} /// Visit call void vCall(Call& c) { std::vector tv(c.n_args()); for (unsigned int i=c.n_args(); i--;) { tv[i] = c.arg(i)->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = env.output->matchFn(env,c.id(), tv, false); Type t; if (decl==NULL) { FunctionI* origdecl = env.model->matchFn(env, c.id(), tv, false); if (origdecl == NULL) { throw FlatteningError(env,c.loc(),"function "+c.id().str()+" is used in output, par version needed"); } bool seen = (seen_functions.find(origdecl) != seen_functions.end()); if (seen) { success = false; } else { seen_functions.insert(origdecl); if (origdecl->e() && cannotUseRHSForOutput(env, origdecl->e(), seen_functions)) { success = false; } else { if (!origdecl->from_stdlib()) { decl = copy(env,env.cmap,origdecl)->cast(); CollectOccurrencesE ce(env.output_vo,decl); topDown(ce, decl->e()); topDown(ce, decl->ti()); for (unsigned int i = decl->params().size(); i--;) topDown(ce, decl->params()[i]); env.output->registerFn(env, decl); env.output->addItem(decl); outputVarDecls(env,origdecl,decl->e()); outputVarDecls(env,origdecl,decl->ti()); } else { decl = origdecl; } c.decl(decl); } } } if (success) { t = decl->rtype(env, tv, false); if (!t.ispar()) success = false; } } void vId(const Id& id) {} /// Visit let void vLet(const Let&) { success = false; } /// Visit variable declaration void vVarDecl(const VarDecl& vd) {} /// Visit type inst void vTypeInst(const TypeInst&) {} /// Visit TIId void vTIId(const TIId&) {} /// Determine whether to enter node bool enter(Expression* e) { return success; } } _v(env, seen_functions); topDown(_v, e); return !_v.success; } bool cannotUseRHSForOutput(EnvI& env, Expression* e) { std::unordered_set seen_functions; return cannotUseRHSForOutput(env, e, seen_functions); } void removeIsOutput(VarDecl* vd) { if (vd==NULL) return; vd->ann().remove(constants().ann.output_var); vd->ann().removeCall(constants().ann.output_array); } void copyOutput(EnvI& e) { struct CopyOutput : public EVisitor { EnvI& env; CopyOutput(EnvI& env0) : env(env0) {} void vId(Id& _id) { _id.decl(_id.decl()->flat()); } void vCall(Call& c) { std::vector tv(c.n_args()); for (unsigned int i=c.n_args(); i--;) { tv[i] = c.arg(i)->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = c.decl(); if (!decl->from_stdlib()) { env.flat_addItem(decl); } } }; if (OutputI* oi = e.model->outputItem()) { GCLock lock; OutputI* noi = copy(e,oi)->cast(); CopyOutput co(e); topDown(co, noi->e()); e.flat_addItem(noi); } } void cleanupOutput(EnvI& env) { for (unsigned int i=0; isize(); i++) { if (VarDeclI* vdi = (*env.output)[i]->dyn_cast()) { vdi->e()->flat(NULL); } } } void makePar(EnvI& env, Expression* e) { class OutputJSON : public EVisitor { public: EnvI& env; OutputJSON(EnvI& env0) : env(env0) {} void vCall(Call& c) { if (c.id()=="outputJSON") { bool outputObjective = (c.n_args()==1 && eval_bool(env,c.arg(0))); c.id(ASTString("array1d")); Expression* json = copy(env, env.cmap, createJSONOutput(env, outputObjective, false)); std::vector new_args({json}); new_args[0]->type(Type::parstring(1)); c.args(new_args); } } } _outputJSON(env); topDown(_outputJSON, e); class Par : public EVisitor { public: /// Visit variable declaration void vVarDecl(VarDecl& vd) { vd.ti()->type(vd.type()); } /// Determine whether to enter node bool enter(Expression* e) { Type t = e->type(); t.ti(Type::TI_PAR); e->type(t); return true; } } _par; topDown(_par, e); class Decls : public EVisitor { protected: static std::string createEnumToStringName(Id* ident, std::string prefix) { std::string name = ident->str().str(); if (name[0]=='\'') { name = "'"+prefix+name.substr(1); } else { name = prefix+name; } return name; } public: EnvI& env; Decls(EnvI& env0) : env(env0) {} void vCall(Call& c) { if (c.id()=="format" || c.id()=="show" || c.id()=="showDzn" || c.id()=="showJSON") { int enumId = c.arg(c.n_args()-1)->type().enumId(); if (enumId != 0 && c.arg(c.n_args()-1)->type().dim() != 0) { const std::vector& enumIds = env.getArrayEnum(enumId); enumId = enumIds[enumIds.size()-1]; } if (enumId > 0) { Id* ti_id = env.getEnum(enumId)->e()->id(); GCLock lock; std::vector args(3); args[0] = c.arg(c.n_args()-1); if (args[0]->type().dim() > 1) { std::vector a1dargs(1); a1dargs[0] = args[0]; Call* array1d = new Call(Location().introduce(),ASTString("array1d"),a1dargs); Type array1dt = args[0]->type(); array1dt.dim(1); array1d->type(array1dt); args[0] = array1d; } args[1] = constants().boollit(c.id()=="showDzn"); args[2] = constants().boollit(c.id()=="showJSON"); std::string enumName = createEnumToStringName(ti_id, "_toString_"); c.id(ASTString(enumName)); c.args(args); } if (c.id()=="showDzn" || (c.id()=="showJSON" && enumId > 0)) { c.id(constants().ids.show); } } c.decl(env.model->matchFn(env,&c,false)); } } _decls(env); topDown(_decls, e); } void checkRenameVar(EnvI& e, VarDecl* vd) { if (vd->id()->idn() != vd->flat()->id()->idn()) { TypeInst* vd_rename_ti = copy(e,e.cmap,vd->ti())->cast(); VarDecl* vd_rename = new VarDecl(Location().introduce(), vd_rename_ti, vd->flat()->id()->idn(), NULL); vd_rename->flat(vd->flat()); makePar(e,vd_rename); vd->e(vd_rename->id()); e.output->addItem(new VarDeclI(Location().introduce(), vd_rename)); } } class ClearAnnotations { public: /// Push all elements of \a v onto \a stack template static void pushVec(std::vector& stack, ASTExprVec v) { for (unsigned int i=0; i stack; stack.push_back(root); while (!stack.empty()) { Expression* e = stack.back(); stack.pop_back(); if (e==NULL) { continue; } e->ann().clear(); switch (e->eid()) { case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_BOOLLIT: case Expression::E_STRINGLIT: case Expression::E_ID: case Expression::E_ANON: case Expression::E_TIID: break; case Expression::E_SETLIT: pushVec(stack, e->template cast()->v()); break; case Expression::E_ARRAYLIT: for (unsigned int i=0; icast()->size(); i++) { stack.push_back((*e->cast())[i]); } break; case Expression::E_ARRAYACCESS: pushVec(stack, e->template cast()->idx()); stack.push_back(e->template cast()->v()); break; case Expression::E_COMP: { Comprehension* comp = e->template cast(); for (unsigned int i=comp->n_generators(); i--; ) { stack.push_back(comp->where(i)); stack.push_back(comp->in(i)); for (unsigned int j=comp->n_decls(i); j--; ) { stack.push_back(comp->decl(i, j)); } } stack.push_back(comp->e()); } break; case Expression::E_ITE: { ITE* ite = e->template cast(); stack.push_back(ite->e_else()); for (int i=0; isize(); i++) { stack.push_back(ite->e_if(i)); stack.push_back(ite->e_then(i)); } } break; case Expression::E_BINOP: stack.push_back(e->template cast()->rhs()); stack.push_back(e->template cast()->lhs()); break; case Expression::E_UNOP: stack.push_back(e->template cast()->e()); break; case Expression::E_CALL: for (unsigned int i=0; itemplate cast()->n_args(); i++) stack.push_back(e->template cast()->arg(i)); break; case Expression::E_VARDECL: stack.push_back(e->template cast()->e()); stack.push_back(e->template cast()->ti()); break; case Expression::E_LET: stack.push_back(e->template cast()->in()); pushVec(stack, e->template cast()->let()); break; case Expression::E_TI: stack.push_back(e->template cast()->domain()); pushVec(stack,e->template cast()->ranges()); break; } } } }; void outputVarDecls(EnvI& env, Item* ci, Expression* e) { class O : public EVisitor { public: EnvI& env; Item* ci; O(EnvI& env0, Item* ci0) : env(env0), ci(ci0) {} void vId(Id& id) { if (&id==constants().absent) return; if (!id.decl()->toplevel()) return; VarDecl* vd = id.decl(); VarDecl* reallyFlat = vd->flat(); while (reallyFlat != NULL && reallyFlat != reallyFlat->flat()) reallyFlat = reallyFlat->flat(); IdMap::iterator idx = reallyFlat ? env.output_vo_flat.idx.find(reallyFlat->id()) : env.output_vo_flat.idx.end(); IdMap::iterator idx2 = env.output_vo.idx.find(vd->id()); if (idx==env.output_vo_flat.idx.end() && idx2==env.output_vo.idx.end()) { VarDeclI* nvi = new VarDeclI(Location().introduce(), copy(env,env.cmap,vd)->cast()); Type t = nvi->e()->ti()->type(); if (t.ti() != Type::TI_PAR) { t.ti(Type::TI_PAR); } makePar(env,nvi->e()); nvi->e()->ti()->domain(NULL); nvi->e()->flat(vd->flat()); ClearAnnotations::run(nvi->e()); nvi->e()->introduced(false); if (reallyFlat) env.output_vo_flat.add_idx(reallyFlat, env.output->size()); env.output_vo.add_idx(nvi, env.output->size()); env.output_vo.add(nvi->e(), ci); env.output->addItem(nvi); IdMap::iterator it; if ( (it = env.reverseMappers.find(nvi->e()->id())) != env.reverseMappers.end()) { Call* rhs = copy(env,env.cmap,it->second())->cast(); { std::vector tv(rhs->n_args()); for (unsigned int i=rhs->n_args(); i--;) { tv[i] = rhs->arg(i)->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = env.output->matchFn(env, rhs->id(), tv, false); if (decl==NULL) { FunctionI* origdecl = env.model->matchFn(env, rhs->id(), tv, false); if (origdecl == NULL) { throw FlatteningError(env,rhs->loc(),"function "+rhs->id().str()+" is used in output, par version needed"); } if (!origdecl->from_stdlib()) { decl = copy(env,env.cmap,origdecl)->cast(); CollectOccurrencesE ce(env.output_vo,decl); topDown(ce, decl->e()); topDown(ce, decl->ti()); for (unsigned int i = decl->params().size(); i--;) topDown(ce, decl->params()[i]); env.output->registerFn(env, decl); env.output->addItem(decl); } else { decl = origdecl; } } rhs->type(decl->rtype(env, tv, false)); rhs->decl(decl); } outputVarDecls(env,nvi,it->second()); nvi->e()->e(rhs); } else if (reallyFlat && cannotUseRHSForOutput(env, reallyFlat->e())) { assert(nvi->e()->flat()); nvi->e()->e(NULL); if (nvi->e()->type().dim() == 0) { reallyFlat->addAnnotation(constants().ann.output_var); } else { std::vector args(reallyFlat->e()->type().dim()); for (unsigned int i=0; ie()->ti()->ranges()[i]->domain() == NULL) { args[i] = new SetLit(Location().introduce(), eval_intset(env,reallyFlat->ti()->ranges()[i]->domain())); } else { args[i] = new SetLit(Location().introduce(), eval_intset(env,nvi->e()->ti()->ranges()[i]->domain())); } } ArrayLit* al = new ArrayLit(Location().introduce(), args); args.resize(1); args[0] = al; reallyFlat->addAnnotation(new Call(Location().introduce(),constants().ann.output_array,args)); } checkRenameVar(env, nvi->e()); } else { outputVarDecls(env, nvi, nvi->e()->ti()); outputVarDecls(env, nvi, nvi->e()->e()); } CollectOccurrencesE ce(env.output_vo,nvi); topDown(ce, nvi->e()); } } } _o(env,ci); topDown(_o, e); } void processDeletions(EnvI& e, std::vector& deletedFlatVarDecls) { std::vector deletedVarDecls; for (unsigned int i=0; isize(); i++) { if (VarDeclI* vdi = (*e.output)[i]->dyn_cast()) { if (!vdi->removed() && e.output_vo.occurrences(vdi->e())==0 && !vdi->e()->ann().contains(constants().ann.mzn_check_var) && !(vdi->e()->id()->idn()==-1 && vdi->e()->id()->v()=="_mzn_solution_checker")) { CollectDecls cd(e.output_vo,deletedVarDecls,vdi); topDown(cd, vdi->e()->e()); removeIsOutput(vdi->e()->flat()); if (e.output_vo.find(vdi->e())!=-1) e.output_vo.remove(vdi->e()); vdi->remove(); } } } while (!deletedVarDecls.empty()) { VarDecl* cur = deletedVarDecls.back(); deletedVarDecls.pop_back(); if (e.output_vo.occurrences(cur) == 0) { IdMap::iterator cur_idx = e.output_vo.idx.find(cur->id()); if (cur_idx != e.output_vo.idx.end()) { VarDeclI* vdi = (*e.output)[cur_idx->second]->cast(); if (!vdi->removed()) { CollectDecls cd(e.output_vo,deletedVarDecls,vdi); topDown(cd,cur->e()); removeIsOutput(vdi->e()->flat()); if (e.output_vo.find(vdi->e())!=-1) e.output_vo.remove(vdi->e()); vdi->remove(); } } } } for (IdMap::iterator it = e.output_vo._m.begin(); it != e.output_vo._m.end(); ++it) { std::vector toRemove; for (VarOccurrences::Items::iterator iit = it->second.begin(); iit != it->second.end(); ++iit) { if ((*iit)->removed()) { toRemove.push_back(*iit); } } for (unsigned int i=0; isecond.erase(toRemove[i]); } } } void createDznOutputItem(EnvI& e, bool outputObjective, bool includeOutputItem) { std::vector outputVars; class DZNOVisitor : public ItemVisitor { protected: EnvI& e; bool outputObjective; bool includeOutputItem; std::vector& outputVars; bool had_add_to_output; public: DZNOVisitor(EnvI& e0, bool outputObjective0, bool includeOutputItem0, std::vector& outputVars0) : e(e0), outputObjective(outputObjective0), outputVars(outputVars0), includeOutputItem(includeOutputItem0), had_add_to_output(false) {} void vVarDeclI(VarDeclI* vdi) { VarDecl* vd = vdi->e(); bool process_var = false; if (outputObjective && vd->id()->idn()==-1 && vd->id()->v()=="_objective") { process_var = true; } else { if (vd->ann().contains(constants().ann.add_to_output)) { if (!had_add_to_output) { outputVars.clear(); } had_add_to_output = true; process_var = true; } else { if (!had_add_to_output) { process_var = false; if (vd->type().isvar()) { if (vd->e()) { if (ArrayLit* al = vd->e()->dyn_cast()) { for (unsigned int i=0; isize(); i++) { if ((*al)[i]->isa()) { process_var = true; break; } } } else if (vd->ann().contains(constants().ann.rhs_from_assignment)) { process_var = true; } } else { process_var = true; } } } } } if (process_var) { std::ostringstream s; s << vd->id()->str().str() << " = "; if (vd->type().dim() > 0) { ArrayLit* al = NULL; if (vd->flat() && vd->flat()->e()) { al = eval_array_lit(e, vd->flat()->e()); } else if (vd->e()) { al = eval_array_lit(e, vd->e()); } s << "array" << vd->type().dim() << "d("; for (int i=0; itype().dim(); i++) { unsigned int enumId = (vd->type().enumId() != 0 ? e.getArrayEnum(vd->type().enumId())[i] : 0); if (enumId != 0) { s << e.getEnum(enumId)->e()->id()->str() << ", "; } else if (al != NULL) { s << al->min(i) << ".." << al->max(i) << ", "; } else { IntSetVal* idxset = eval_intset(e,vd->ti()->ranges()[i]->domain()); s << *idxset << ", "; } } } StringLit* sl = new StringLit(Location().introduce(),s.str()); outputVars.push_back(sl); std::vector showArgs(1); showArgs[0] = vd->id(); Call* show = new Call(Location().introduce(),ASTString("showDzn"),showArgs); show->type(Type::parstring()); FunctionI* fi = e.model->matchFn(e, show, false); assert(fi); show->decl(fi); outputVars.push_back(show); std::string ends = vd->type().dim() > 0 ? ")" : ""; ends += ";\n"; StringLit* eol = new StringLit(Location().introduce(),ends); outputVars.push_back(eol); } } void vOutputI(OutputI* oi) { if (includeOutputItem) { outputVars.push_back(new StringLit(Location().introduce(), "_output = ")); Call* concat = new Call(Location().introduce(), ASTString("concat"), {oi->e()}); concat->type(Type::parstring()); FunctionI* fi = e.model->matchFn(e, concat, false); assert(fi); concat->decl(fi); Call* show = new Call(Location().introduce(), ASTString("showDzn"), {concat}); show->type(Type::parstring()); fi = e.model->matchFn(e, show, false); assert(fi); show->decl(fi); outputVars.push_back(show); outputVars.push_back(new StringLit(Location().introduce(), ";\n")); } oi->remove(); } } dznov(e, outputObjective, includeOutputItem, outputVars); iterItems(dznov, e.model); OutputI* newOutputItem = new OutputI(Location().introduce(),new ArrayLit(Location().introduce(),outputVars)); e.model->addItem(newOutputItem); } ArrayLit* createJSONOutput(EnvI& e, bool outputObjective, bool includeOutputItem) { std::vector outputVars; outputVars.push_back(new StringLit(Location().introduce(), "{\n")); class JSONOVisitor : public ItemVisitor { protected: EnvI& e; bool outputObjective; bool includeOutputItem; std::vector& outputVars; bool had_add_to_output; bool first_var; public: JSONOVisitor(EnvI& e0, bool outputObjective0, bool includeOutputItem0, std::vector& outputVars0) : e(e0), outputObjective(outputObjective0), outputVars(outputVars0), includeOutputItem(includeOutputItem0), had_add_to_output(false), first_var(true) {} void vVarDeclI(VarDeclI* vdi) { VarDecl* vd = vdi->e(); bool process_var = false; if (outputObjective && vd->id()->idn()==-1 && vd->id()->v()=="_objective") { process_var = true; } else { if (vd->ann().contains(constants().ann.add_to_output)) { if (!had_add_to_output) { outputVars.clear(); outputVars.push_back(new StringLit(Location().introduce(), "{\n")); first_var = true; } had_add_to_output = true; process_var = true; } else { if (!had_add_to_output) { process_var = vd->type().isvar() && (vd->e()==NULL || vd->ann().contains(constants().ann.rhs_from_assignment)); } } } if (process_var) { std::ostringstream s; if (first_var) { first_var = false; } else { s << ",\n"; } s << " \"" << vd->id()->str().str() << "\"" << " : "; StringLit* sl = new StringLit(Location().introduce(),s.str()); outputVars.push_back(sl); std::vector showArgs(1); showArgs[0] = vd->id(); Call* show = new Call(Location().introduce(),"showJSON",showArgs); show->type(Type::parstring()); FunctionI* fi = e.model->matchFn(e, show, false); assert(fi); show->decl(fi); outputVars.push_back(show); } } void vOutputI(OutputI* oi) { if (includeOutputItem) { std::ostringstream s; if (first_var) { first_var = false; } else { s << ",\n"; } s << " \"_output\"" << " : "; StringLit* sl = new StringLit(Location().introduce(),s.str()); outputVars.push_back(sl); Call* concat = new Call(Location().introduce(), ASTString("concat"), {oi->e()}); concat->type(Type::parstring()); FunctionI* fi = e.model->matchFn(e, concat, false); assert(fi); concat->decl(fi); Call* show = new Call(Location().introduce(), ASTString("showJSON"), {concat}); show->type(Type::parstring()); fi = e.model->matchFn(e, show, false); assert(fi); show->decl(fi); outputVars.push_back(show); } oi->remove(); } } jsonov(e, outputObjective, includeOutputItem, outputVars); iterItems(jsonov, e.model); outputVars.push_back(new StringLit(Location().introduce(), "\n}\n")); return new ArrayLit(Location().introduce(),outputVars); } void createJSONOutputItem(EnvI& e, bool outputObjective, bool includeOutputItem) { OutputI* newOutputItem = new OutputI(Location().introduce(), createJSONOutput(e, outputObjective, includeOutputItem)); e.model->addItem(newOutputItem); } void createOutput(EnvI& e, std::vector& deletedFlatVarDecls, FlatteningOptions::OutputMode outputMode, bool outputObjective, bool includeOutputItem) { // Create new output model OutputI* outputItem = NULL; GCLock lock; switch (outputMode) { case FlatteningOptions::OUTPUT_DZN: createDznOutputItem(e,outputObjective, includeOutputItem); break; case FlatteningOptions::OUTPUT_JSON: createJSONOutputItem(e, outputObjective, includeOutputItem); default: if (e.model->outputItem()==NULL) { createDznOutputItem(e, outputObjective, false); } break; } // Copy output item from model into output model outputItem = copy(e,e.cmap, e.model->outputItem())->cast(); makePar(e,outputItem->e()); e.output->addItem(outputItem); // Copy all function definitions that are required for output into the output model class CollectFunctions : public EVisitor { public: EnvI& env; CollectFunctions(EnvI& env0) : env(env0) {} bool enter(Expression* e) { if (e->type().isvar()) { Type t = e->type(); t.ti(Type::TI_PAR); e->type(t); } return true; } void vCall(Call& c) { std::vector tv(c.n_args()); for (unsigned int i=c.n_args(); i--;) { tv[i] = c.arg(i)->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = env.output->matchFn(env, c.id(), tv, false); FunctionI* origdecl = env.model->matchFn(env, c.id(), tv, false); bool canReuseDecl = (decl != nullptr); if (canReuseDecl && origdecl) { // Check if this is the exact same overloaded declaration as in the model for (unsigned int i=0; iparams().size(); i++) { if (decl->params()[i]->type() != origdecl->params()[i]->type()) { // no, the types don't match, so we have to copy the original decl canReuseDecl = false; break; } } } Type t; if (!canReuseDecl) { if (origdecl == NULL || !origdecl->rtype(env, tv, false).ispar()) { throw FlatteningError(env,c.loc(),"function "+c.id().str()+" is used in output, par version needed"); } if (!origdecl->from_stdlib()) { FunctionI* decl_copy = copy(env,env.cmap,origdecl)->cast(); if (decl_copy != decl) { decl = decl_copy; env.output->registerFn(env, decl); env.output->addItem(decl); if (decl->e()) { makePar(env, decl->e()); topDown(*this, decl->e()); } CollectOccurrencesE ce(env.output_vo,decl); topDown(ce, decl->e()); topDown(ce, decl->ti()); for (unsigned int i = decl->params().size(); i--;) topDown(ce, decl->params()[i]); } } else { decl = origdecl; } } c.decl(decl); } } _cf(e); topDown(_cf, outputItem->e()); // If we are checking solutions using a checker model, all parameters of the checker model // have to be made available in the output model class OV1 : public ItemVisitor { public: EnvI& env; CollectFunctions& _cf; OV1(EnvI& env0, CollectFunctions& cf) : env(env0), _cf(cf) {} void vVarDeclI(VarDeclI* vdi) { if (vdi->e()->ann().contains(constants().ann.mzn_check_var)) { VarDecl* output_vd = copy(env,env.cmap,vdi->e())->cast(); topDown(_cf, output_vd); } } } _ov1(e, _cf); iterItems(_ov1, e.model); // Copying the output item and the functions it depends on has created copies // of all dependent VarDecls. However the output model does not contain VarDeclIs for // these VarDecls yet. This iterator processes all variable declarations of the // original model, and if they were copied (i.e., if the output model depends on them), // the corresponding VarDeclI is created in the output model. class OV2 : public ItemVisitor { public: EnvI& env; OV2(EnvI& env0) : env(env0) {} void vVarDeclI(VarDeclI* vdi) { IdMap::iterator idx = env.output_vo.idx.find(vdi->e()->id()); if (idx!=env.output_vo.idx.end()) return; if (Expression* vd_e = env.cmap.find(vdi->e())) { // We found a copied VarDecl, now need to create a VarDeclI VarDecl* vd = vd_e->cast(); VarDeclI* vdi_copy = copy(env,env.cmap,vdi)->cast(); Type t = vdi_copy->e()->ti()->type(); t.ti(Type::TI_PAR); vdi_copy->e()->ti()->domain(NULL); vdi_copy->e()->flat(vdi->e()->flat()); bool isCheckVar = vdi_copy->e()->ann().contains(constants().ann.mzn_check_var); Call* checkVarEnum = vdi_copy->e()->ann().getCall(constants().ann.mzn_check_enum_var); vdi_copy->e()->ann().clear(); if (isCheckVar) { vdi_copy->e()->ann().add(constants().ann.mzn_check_var); } if (checkVarEnum) { vdi_copy->e()->ann().add(checkVarEnum); } vdi_copy->e()->introduced(false); IdMap::iterator it; if (!vdi->e()->type().ispar()) { if (vd->flat() == NULL && vdi->e()->e()!=NULL && vdi->e()->e()->type().ispar()) { // Don't have a flat version of this variable, but the original has a right hand // side that is par, so we can use that. Expression* flate = eval_par(env, vdi->e()->e()); outputVarDecls(env,vdi_copy,flate); vd->e(flate); } else { vd = follow_id_to_decl(vd->id())->cast(); VarDecl* reallyFlat = vd->flat(); while (reallyFlat && reallyFlat!=reallyFlat->flat()) reallyFlat=reallyFlat->flat(); if (reallyFlat==NULL) { // The variable doesn't have a flat version. This can only happen if // the original variable had type-inst var, but a right-hand-side that // was par, so follow_id_to_decl lead to a par variable. assert(vd->e() && vd->e()->type().ispar()); Expression* flate = eval_par(env, vd->e()); outputVarDecls(env, vdi_copy, flate); vd->e(flate); } else if (vd->flat()->e() && vd->flat()->e()->type().ispar()) { // We can use the right hand side of the flat version of this variable Expression* flate = copy(env,env.cmap,follow_id(reallyFlat->id())); outputVarDecls(env,vdi_copy,flate); vd->e(flate); } else if ( (it = env.reverseMappers.find(vd->id())) != env.reverseMappers.end()) { // Found a reverse mapper, so we need to add the mapping function to the // output model to map the FlatZinc value back to the model variable. Call* rhs = copy(env,env.cmap,it->second())->cast(); { std::vector tv(rhs->n_args()); for (unsigned int i=rhs->n_args(); i--;) { tv[i] = rhs->arg(i)->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = env.output->matchFn(env, rhs->id(), tv, false); if (decl==NULL) { FunctionI* origdecl = env.model->matchFn(env, rhs->id(), tv, false); if (origdecl == NULL) { throw FlatteningError(env,rhs->loc(),"function "+rhs->id().str()+" is used in output, par version needed"); } if (!origdecl->from_stdlib()) { decl = copy(env,env.cmap,origdecl)->cast(); CollectOccurrencesE ce(env.output_vo,decl); topDown(ce, decl->e()); topDown(ce, decl->ti()); for (unsigned int i = decl->params().size(); i--;) topDown(ce, decl->params()[i]); env.output->registerFn(env, decl); env.output->addItem(decl); } else { decl = origdecl; } } rhs->decl(decl); } outputVarDecls(env,vdi_copy,rhs); vd->e(rhs); } else if (cannotUseRHSForOutput(env,vd->e())) { // If the VarDecl does not have a usable right hand side, it needs to be // marked as output in the FlatZinc vd->e(NULL); assert(vd->flat()); if (vd->type().dim() == 0) { vd->flat()->addAnnotation(constants().ann.output_var); checkRenameVar(env, vd); } else { bool needOutputAnn = true; if (reallyFlat->e() && reallyFlat->e()->isa()) { ArrayLit* al = reallyFlat->e()->cast(); for (unsigned int i=0; isize(); i++) { if (Id* id = (*al)[i]->dyn_cast()) { if (env.reverseMappers.find(id) != env.reverseMappers.end()) { needOutputAnn = false; break; } } } if (!needOutputAnn) { outputVarDecls(env, vdi_copy, al); vd->e(copy(env,env.cmap,al)); } } if (needOutputAnn) { std::vector args(vdi->e()->type().dim()); for (unsigned int i=0; ie()->ti()->ranges()[i]->domain() == NULL) { args[i] = new SetLit(Location().introduce(), eval_intset(env,vd->flat()->ti()->ranges()[i]->domain())); } else { args[i] = new SetLit(Location().introduce(), eval_intset(env,vd->ti()->ranges()[i]->domain())); } } ArrayLit* al = new ArrayLit(Location().introduce(), args); args.resize(1); args[0] = al; vd->flat()->addAnnotation(new Call(Location().introduce(),constants().ann.output_array,args)); checkRenameVar(env, vd); } } } if (reallyFlat && env.output_vo_flat.find(reallyFlat) == -1) env.output_vo_flat.add_idx(reallyFlat, env.output->size()); } } else { if (vd->flat() == NULL && vdi->e()->e()!=NULL) { // Need to process right hand side of variable, since it may contain // identifiers that are only in the FlatZinc and that we would // therefore fail to copy into the output model outputVarDecls(env,vdi_copy,vdi->e()->e()); } } makePar(env,vdi_copy->e()); env.output_vo.add_idx(vdi_copy, env.output->size()); CollectOccurrencesE ce(env.output_vo,vdi_copy); topDown(ce, vdi_copy->e()); env.output->addItem(vdi_copy); } } } _ov2(e); iterItems(_ov2,e.model); CollectOccurrencesE ce(e.output_vo,outputItem); topDown(ce, outputItem->e()); e.model->mergeStdLib(e, e.output); processDeletions(e, deletedFlatVarDecls); } Expression* isFixedDomain(EnvI& env, VarDecl* vd) { if (vd->type()!=Type::varbool() && vd->type()!=Type::varint() && vd->type()!=Type::varfloat()) return NULL; Expression* e = vd->ti()->domain(); if (e==constants().lit_true || e==constants().lit_false) return e; if (SetLit* sl = Expression::dyn_cast(e)) { if (sl->type().bt()==Type::BT_INT) { IntSetVal* isv = eval_intset(env, sl); return isv->min()==isv->max() ? IntLit::a(isv->min()) : NULL; } else if (sl->type().bt()==Type::BT_FLOAT) { FloatSetVal* fsv = eval_floatset(env, sl); return fsv->min()==fsv->max() ? FloatLit::a(fsv->min()) : NULL; } } return NULL; } void finaliseOutput(EnvI& e, std::vector& deletedFlatVarDecls) { if (e.output->size() > 0) { // Adapt existing output model // (generated by repeated flattening) e.output_vo.clear(); for (unsigned int i=0; isize(); i++) { Item* item = (*e.output)[i]; if (item->removed()) continue; switch (item->iid()) { case Item::II_VD: { VarDecl* vd = item->cast()->e(); IdMap::iterator it; GCLock lock; VarDecl* reallyFlat = vd->flat(); while (reallyFlat && reallyFlat!=reallyFlat->flat()) reallyFlat=reallyFlat->flat(); if (vd->e()==NULL) { if ( (vd->flat()->e() && vd->flat()->e()->type().ispar()) || isFixedDomain(e, vd->flat()) ) { VarDecl* reallyFlat = vd->flat(); while (reallyFlat!=reallyFlat->flat()) reallyFlat=reallyFlat->flat(); removeIsOutput(reallyFlat); Expression* flate; if (Expression* fd = isFixedDomain(e, vd->flat())) { flate = fd; } else { flate = copy(e,e.cmap,follow_id(reallyFlat->id())); } outputVarDecls(e,item,flate); vd->e(flate); } else if ( (it = e.reverseMappers.find(vd->id())) != e.reverseMappers.end()) { Call* rhs = copy(e,e.cmap,it->second())->cast(); std::vector tv(rhs->n_args()); for (unsigned int i=rhs->n_args(); i--;) { tv[i] = rhs->arg(i)->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = e.output->matchFn(e, rhs->id(), tv, false); if (decl==NULL) { FunctionI* origdecl = e.model->matchFn(e, rhs->id(), tv, false); if (origdecl == NULL) { throw FlatteningError(e,rhs->loc(),"function "+rhs->id().str()+" is used in output, par version needed"); } if (!origdecl->from_stdlib()) { decl = copy(e,e.cmap,origdecl)->cast(); CollectOccurrencesE ce(e.output_vo,decl); topDown(ce, decl->e()); topDown(ce, decl->ti()); for (unsigned int i = decl->params().size(); i--;) topDown(ce, decl->params()[i]); e.output->registerFn(e, decl); e.output->addItem(decl); } else { decl = origdecl; } } rhs->decl(decl); removeIsOutput(reallyFlat); if (e.vo.occurrences(reallyFlat)==0 && reallyFlat->e()==NULL) { deletedFlatVarDecls.push_back(reallyFlat); } outputVarDecls(e,item,it->second()->cast()); vd->e(rhs); } else { // If the VarDecl does not have a usable right hand side, it needs to be // marked as output in the FlatZinc assert(vd->flat()); bool needOutputAnn = true; if (reallyFlat->e() && reallyFlat->e()->isa()) { ArrayLit* al = reallyFlat->e()->cast(); for (unsigned int i=0; isize(); i++) { if (Id* id = (*al)[i]->dyn_cast()) { if (e.reverseMappers.find(id) != e.reverseMappers.end()) { needOutputAnn = false; break; } } } if (!needOutputAnn) { removeIsOutput(vd); removeIsOutput(reallyFlat); if (e.vo.occurrences(reallyFlat)==0) { deletedFlatVarDecls.push_back(reallyFlat); } outputVarDecls(e, item, al); vd->e(copy(e,e.cmap,al)); Type al_t(vd->e()->type()); al_t.ti(Type::TI_PAR); vd->e()->type(al_t); } } if (needOutputAnn) { if (!isOutput(vd->flat())) { GCLock lock; if (vd->type().dim() == 0) { vd->flat()->addAnnotation(constants().ann.output_var); } else { std::vector args(vd->type().dim()); for (unsigned int i=0; iti()->ranges()[i]->domain() == NULL) { args[i] = new SetLit(Location().introduce(), eval_intset(e,vd->flat()->ti()->ranges()[i]->domain())); } else { args[i] = new SetLit(Location().introduce(), eval_intset(e,vd->ti()->ranges()[i]->domain())); } } ArrayLit* al = new ArrayLit(Location().introduce(), args); args.resize(1); args[0] = al; vd->flat()->addAnnotation(new Call(Location().introduce(),constants().ann.output_array,args)); } checkRenameVar(e, vd); } } } vd->flat(NULL); // Remove enum type Type vdt = vd->type(); vdt.enumId(0); vd->type(vdt); vd->ti()->type(vdt); } e.output_vo.add_idx(item->cast(), i); CollectOccurrencesE ce(e.output_vo,item); topDown(ce, vd); } break; case Item::II_OUT: { CollectOccurrencesE ce(e.output_vo,item); topDown(ce, item->cast()->e()); } break; case Item::II_FUN: { CollectOccurrencesE ce(e.output_vo,item); topDown(ce, item->cast()->e()); topDown(ce, item->cast()->ti()); for (unsigned int i = item->cast()->params().size(); i--;) topDown(ce, item->cast()->params()[i]); } break; default: throw FlatteningError(e,item->loc(), "invalid item in output model"); } } } processDeletions(e, deletedFlatVarDecls); } } libminizinc-2.4.2/lib/parser.cpp000066400000000000000000000277261360574160400166200ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* This (main) file coordinates flattening and solving. * The corresponding modules are flexibly plugged in * as derived classes, prospectively from DLLs. * A flattening module should provide MinZinc::GetFlattener() * A solving module should provide an object of a class derived from SolverFactory. * Need to get more flexible for multi-pass & multi-solving stuff TODO */ #include #include #include #include #include using namespace std; int mzn_yylex_init (void** scanner); void mzn_yyset_extra (void* user_defined ,void* yyscanner ); int mzn_yyparse(void*); int mzn_yylex_destroy (void* scanner); namespace { // fastest way to read a file into a string (especially big files) // see: http://insanecoding.blogspot.be/2011/11/how-to-read-in-file-in-c.html std::string get_file_contents(std::ifstream &in) { if (in) { std::string contents; in.seekg(0, std::ios::end); contents.resize(static_cast(in.tellg())); in.seekg(0, std::ios::beg); in.read(&contents[0], contents.size()); in.close(); if (contents.size() > 0 && contents[0]=='@') { contents = MiniZinc::FileUtils::decodeBase64(contents); MiniZinc::FileUtils::inflateString(contents); } return(contents); } throw(errno); } } namespace MiniZinc { void parse(Env& env, Model*& model, const vector& filenames, const vector& datafiles, const std::string& modelString, const std::string& modelStringName, const vector& ip, bool ignoreStdlib, bool parseDocComments, bool verbose, ostream& err, std::vector& syntaxErrors) { vector includePaths; for (unsigned int i=0; i files; map seenModels; string workingDir = FileUtils::working_directory(); if (filenames.size() > 0) { GCLock lock; model->setFilename(FileUtils::base_name(filenames[0])); if (FileUtils::is_absolute(filenames[0])) { files.push_back(ParseWorkItem(model,NULL,"",filenames[0])); } else { files.push_back(ParseWorkItem(model,NULL,"",workingDir+"/"+filenames[0])); } for (unsigned int i=1; isetFilename(baseName); files.push_back(ParseWorkItem(includedModel,NULL,"",fullName)); seenModels.insert(pair(baseName,includedModel)); Location loc(ASTString(filenames[i]),0,0,0,0); IncludeI* inc = new IncludeI(loc,includedModel->filename()); inc->m(includedModel,true); model->addItem(inc); } } if (!modelString.empty()) { Model* includedModel = new Model; includedModel->setFilename(modelStringName); files.push_back(ParseWorkItem(includedModel,NULL,modelString,modelStringName,true)); seenModels.insert(pair(modelStringName,includedModel)); Location loc(ASTString(modelStringName),0,0,0,0); IncludeI* inc = new IncludeI(loc,includedModel->filename()); inc->m(includedModel,true); model->addItem(inc); } } else if (!modelString.empty()) { GCLock lock; model->setFilename(modelStringName); files.push_back(ParseWorkItem(model,NULL,modelString,modelStringName,true)); } if (!ignoreStdlib) { GCLock lock; Model* stdlib = new Model; stdlib->setFilename("stdlib.mzn"); files.push_back(ParseWorkItem(stdlib,NULL,"./","stdlib.mzn")); seenModels.insert(pair("stdlib.mzn",stdlib)); Location stdlibloc(ASTString(model->filename()),0,0,0,0); IncludeI* stdlibinc = new IncludeI(stdlibloc,stdlib->filename()); stdlibinc->m(stdlib,true); model->addItem(stdlibinc); } while (!files.empty()) { GCLock lock; ParseWorkItem& np = files.back(); string parentPath = np.dirName; Model* m = np.m; bool isModelString = np.isModelString; IncludeI* np_ii = np.ii; string f(np.fileName); files.pop_back(); std::string s; std::string fullname; bool isFzn; if (!isModelString) { for (Model* p=m->parent(); p; p=p->parent()) { if (f == p->filename().c_str()) { err << "Error: cyclic includes: " << std::endl; for (Model* pe=m; pe; pe=pe->parent()) { err << " " << pe->filename() << std::endl; } goto error; } } ifstream file; if (FileUtils::is_absolute(f) || parentPath=="") { fullname = f; if (FileUtils::file_exists(fullname)) { file.open(fullname.c_str(), std::ios::binary); } } else { includePaths.push_back(parentPath); unsigned int i=0; for (; isetFilename(deprecatedBaseName); files.push_back(ParseWorkItem(includedModel,NULL,"",deprecatedName)); seenModels.insert(pair(deprecatedBaseName,includedModel)); Location loc(ASTString(deprecatedName),0,0,0,0); IncludeI* inc = new IncludeI(loc,includedModel->filename()); inc->m(includedModel,true); m->addItem(inc); files.push_back(ParseWorkItem(includedModel,inc,deprecatedName,deprecatedBaseName)); } } includePaths.pop_back(); } if (!file.is_open()) { if (np_ii) { err << np_ii->loc().toString() << ":\n"; err << "MiniZinc: error in include item, cannot open file '" << f << "'." << endl; } else { err << "Error: cannot open file '" << f << "'." << endl; } goto error; } if (verbose) std::cerr << "processing file '" << fullname << "'" << endl; s = get_file_contents(file); if (m->filepath().size() == 0) m->setFilepath(fullname); isFzn = (fullname.compare(fullname.length()-4,4,".fzn")==0); isFzn |= (fullname.compare(fullname.length()-4,4,".ozn")==0); isFzn |= (fullname.compare(fullname.length()-4,4,".szn")==0); isFzn |= (fullname.compare(fullname.length()-4,4,".mzc")==0); } else { isFzn = false; fullname = f; s = parentPath; } ParserState pp(fullname,s, err, files, seenModels, m, false, isFzn, parseDocComments); mzn_yylex_init(&pp.yyscanner); mzn_yyset_extra(&pp, pp.yyscanner); mzn_yyparse(&pp); if (pp.yyscanner) mzn_yylex_destroy(pp.yyscanner); if (pp.hadError) { for (unsigned int i=0; i=6 && f.substr(f.size()-5,string::npos)==".json") { JSONParser jp(env.envi()); jp.parse(model, f); } else { string s; if (f.size() > 5 && f.substr(0,5)=="cmd:/") { s = f.substr(5); } else { std::ifstream file; file.open(f.c_str(), std::ios::binary); if (!FileUtils::file_exists(f) || !file.is_open()) { err << "Error: cannot open data file '" << f << "'." << endl; goto error; } if (verbose) std::cerr << "processing data file '" << f << "'" << endl; s = get_file_contents(file); } ParserState pp(f, s, err, files, seenModels, model, true, false, parseDocComments); mzn_yylex_init(&pp.yyscanner); mzn_yyset_extra(&pp, pp.yyscanner); mzn_yyparse(&pp); if (pp.yyscanner) mzn_yylex_destroy(pp.yyscanner); if (pp.hadError) { for (unsigned int i=0; i& filenames, const vector& datafiles, const string& textModel, const string& textModelName, const vector& ip, bool ignoreStdlib, bool parseDocComments, bool verbose, ostream& err) { if (filenames.empty() && textModel.empty()) { err << "Error: no model given" << std::endl; return NULL; } Model* model; { GCLock lock; model = new Model(); } std::vector se; parse(env, model, filenames, datafiles, textModel, textModelName, ip, ignoreStdlib, parseDocComments, verbose, err, se); return model; } Model* parseData(Env& env, Model* model, const vector& datafiles, const vector& includePaths, bool ignoreStdlib, bool parseDocComments, bool verbose, ostream& err) { vector filenames; std::vector se; parse(env, model, filenames, datafiles, "", "", includePaths, ignoreStdlib, parseDocComments, verbose, err, se); return model; } Model* parseFromString(Env& env, const string& text, const string& filename, const vector& ip, bool ignoreStdlib, bool parseDocComments, bool verbose, ostream& err, std::vector& syntaxErrors) { vector filenames; vector datafiles; Model* model; { GCLock lock; model = new Model(); } parse(env, model, filenames, datafiles, text, filename, ip, ignoreStdlib, parseDocComments, verbose, err, syntaxErrors); return model; } } libminizinc-2.4.2/lib/parser.yxx000066400000000000000000001407531360574160400166620ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ %pure-parser %parse-param {void *parm} %lex-param {void* SCANNER} %{ #define SCANNER static_cast(parm)->yyscanner #include #include #include #include namespace MiniZinc{ class ParserLocation; } #define YYLTYPE MiniZinc::ParserLocation #define YYLTYPE_IS_DECLARED 1 #define YYLTYPE_IS_TRIVIAL 0 #define YYMAXDEPTH 10000 #define YYINITDEPTH 10000 #include #include using namespace std; using namespace MiniZinc; #define YYLLOC_DEFAULT(Current, Rhs, N) \ Current.filename(Rhs[1].filename()); \ Current.first_line(Rhs[1].first_line()); \ Current.first_column(Rhs[1].first_column()); \ Current.last_line(Rhs[N].last_line()); \ Current.last_column(Rhs[N].last_column()); int mzn_yyparse(void*); int mzn_yylex(YYSTYPE*, YYLTYPE*, void* scanner); int mzn_yylex_init (void** scanner); int mzn_yylex_destroy (void* scanner); int mzn_yyget_lineno (void* scanner); void mzn_yyset_extra (void* user_defined ,void* yyscanner ); extern int yydebug; namespace MiniZinc { void yyerror(YYLTYPE* location, void* parm, const string& str) { ParserState* pp = static_cast(parm); Model* m = pp->model; while (m->parent() != NULL) { m = m->parent(); pp->err << "(included from file '" << m->filename() << "')" << endl; } pp->err << location->toString() << ":" << endl; pp->printCurrentLine(location->first_column(),location->last_column()); pp->err << "Error: " << str << std::endl; pp->hadError = true; pp->syntaxErrors.push_back(SyntaxError(Location(*location), str)); } bool notInDatafile(YYLTYPE* location, void* parm, const string& item) { ParserState* pp = static_cast(parm); if (pp->isDatafile) { yyerror(location,parm,item+" item not allowed in data file"); return false; } return true; } Expression* createDocComment(const ParserLocation& loc, const std::string& s) { std::vector args(1); args[0] = new StringLit(loc, s); Call* c = new Call(Location(loc), constants().ann.doc_comment, args); c->type(Type::ann()); return c; } Expression* createArrayAccess(const ParserLocation& loc, Expression* e, std::vector >& idx) { Expression* ret = e; for (unsigned int i=0; i* vardeclexpr_v; MiniZinc::TypeInst* tiexpr; std::vector* tiexpr_v; MiniZinc::Expression* expression; std::vector* expression_v; std::vector >* expression_vv; std::vector > >* expression_vvv; MiniZinc::Generator* generator; std::vector* generator_v; std::vector* string_v; std::vector >* expression_p; MiniZinc::Generators* generators; } %locations %error-verbose %initial-action { GCLock lock; @$.filename(ASTString(static_cast(parm)->filename)); } %token MZN_INTEGER_LITERAL "integer literal" MZN_BOOL_LITERAL "bool literal" %token MZN_FLOAT_LITERAL "float literal" %token MZN_IDENTIFIER "identifier" MZN_QUOTED_IDENTIFIER "quoted identifier" MZN_STRING_LITERAL "string literal" %token MZN_STRING_QUOTE_START "interpolated string start" MZN_STRING_QUOTE_MID "interpolated string middle" MZN_STRING_QUOTE_END "interpolated string end" %token MZN_TI_IDENTIFIER "type-inst identifier" MZN_TI_ENUM_IDENTIFIER "type-inst enum identifier" MZN_DOC_COMMENT "documentation comment" MZN_DOC_FILE_COMMENT "file-level documentation comment" %token MZN_VAR "var" MZN_PAR "par" %token MZN_ABSENT "<>" %token MZN_ANN "ann" %token MZN_ANNOTATION "annotation" %token MZN_ANY "any" %token MZN_ARRAY "array" %token MZN_BOOL "bool" %token MZN_CASE "case" %token MZN_CONSTRAINT "constraint" %token MZN_DEFAULT "default" %token MZN_ELSE "else" %token MZN_ELSEIF "elseif" %token MZN_ENDIF "endif" %token MZN_ENUM "enum" %token MZN_FLOAT "float" %token MZN_FUNCTION "function" %token MZN_IF "if" %token MZN_INCLUDE "include" %token MZN_INFINITY "infinity" %token MZN_INT "int" %token MZN_LET "let" %token MZN_LIST "list" %token MZN_MAXIMIZE "maximize" %token MZN_MINIMIZE "minimize" %token MZN_OF "of" %token MZN_OPT "opt" %token MZN_SATISFY "satisfy" %token MZN_OUTPUT "output" %token MZN_PREDICATE "predicate" %token MZN_RECORD "record" %token MZN_SET "set" %token MZN_SOLVE "solve" %token MZN_STRING "string" %token MZN_TEST "test" %token MZN_THEN "then" %token MZN_TUPLE "tuple" %token MZN_TYPE "type" %token MZN_UNDERSCORE "_" %token MZN_VARIANT_RECORD "variant_record" %token MZN_WHERE "where" %token MZN_LEFT_BRACKET "[" %token MZN_LEFT_2D_BRACKET "[|" %token MZN_RIGHT_BRACKET "]" %token MZN_RIGHT_2D_BRACKET "|]" // Used to signal an error when parsing a MiniZinc file // that contains identifiers starting with _ %token FLATZINC_IDENTIFIER %token MZN_INVALID_INTEGER_LITERAL "invalid integer literal" %token MZN_INVALID_FLOAT_LITERAL "invalid float literal" %token MZN_UNTERMINATED_STRING "unterminated string" %token MZN_END_OF_LINE_IN_STRING "end of line inside string literal" %token MZN_INVALID_NULL "null character" %token END 0 "end of file" %token MZN_EQUIV "<->" %token MZN_IMPL "->" MZN_RIMPL "<-" %token MZN_OR "\\/" MZN_XOR "xor" %token MZN_AND "/\\" %token MZN_LE "<" MZN_GR ">" MZN_LQ "<=" MZN_GQ ">=" MZN_EQ "=" MZN_NQ "!=" MZN_WEAK_EQ "~=" %token MZN_IN "in" MZN_SUBSET "subset" MZN_SUPERSET "superset" %token MZN_UNION "union" MZN_DIFF "diff" MZN_SYMDIFF "symdiff" %token MZN_DOTDOT ".." %token MZN_PLUS "+" MZN_MINUS "-" MZN_WEAK_PLUS "~+" MZN_WEAK_MINUS "~-" %token MZN_MULT "*" MZN_DIV "/" MZN_IDIV "div" MZN_MOD "mod" MZN_INTERSECT "intersect" MZN_WEAK_MULT "~*" %token MZN_POW "^" %token MZN_NOT "not" %token MZN_PLUSPLUS "++" %token MZN_COLONCOLON "::" %right PREC_ANNO %left MZN_EQUIV %left MZN_IMPL MZN_RIMPL %left MZN_OR MZN_XOR %left MZN_AND %nonassoc MZN_LE MZN_GR MZN_LQ MZN_GQ MZN_EQ MZN_NQ MZN_WEAK_EQ %nonassoc MZN_IN MZN_SUBSET MZN_SUPERSET %left MZN_UNION MZN_DIFF MZN_SYMDIFF MZN_INTERSECT %nonassoc MZN_DOTDOT %left MZN_PLUS MZN_MINUS MZN_WEAK_PLUS MZN_WEAK_MINUS %left MZN_MULT MZN_DIV MZN_IDIV MZN_MOD MZN_WEAK_MULT %left MZN_POW %nonassoc MZN_NOT %left MZN_PLUSPLUS %left MZN_QUOTED_IDENTIFIER %left MZN_COLONCOLON %token MZN_EQUIV_QUOTED "'<->'" %token MZN_IMPL_QUOTED "'->'" MZN_RIMPL_QUOTED "'<-'" %token MZN_OR_QUOTED "'\\/'" MZN_XOR_QUOTED "'xor'" %token MZN_AND_QUOTED "'/\\'" %token MZN_LE_QUOTED "'<'" MZN_GR_QUOTED "'>'" MZN_LQ_QUOTED "'<='" MZN_GQ_QUOTED "'>='" MZN_EQ_QUOTED "'='" MZN_NQ_QUOTED "'!='" %token MZN_IN_QUOTED "'in'" MZN_SUBSET_QUOTED "'subset'" MZN_SUPERSET_QUOTED "'superset'" %token MZN_UNION_QUOTED "'union'" MZN_DIFF_QUOTED "'diff'" MZN_SYMDIFF_QUOTED "'symdiff'" %token MZN_DOTDOT_QUOTED "'..'" %token MZN_PLUS_QUOTED "'+'" MZN_MINUS_QUOTED "'-'" %token MZN_MULT_QUOTED "'*'" MZN_DIV_QUOTED "'/'" MZN_IDIV_QUOTED "'div'" MZN_MOD_QUOTED "'mod'" MZN_INTERSECT_QUOTED "'intersect'" %token MZN_POW_QUOTED "'^'" %token MZN_NOT_QUOTED "'not'" %token MZN_COLONCOLON_QUOTED "'::'" %token MZN_PLUSPLUS_QUOTED "'++'" %type item item_tail include_item vardecl_item assign_item constraint_item solve_item output_item predicate_item annotation_item function_item %type ti_expr_and_id ti_expr_and_id_or_anon let_vardecl_item %type params params_list params_list_head %type ti_expr base_ti_expr base_ti_expr_tail %type ti_expr_list ti_expr_list_head %type expr expr_atom_head expr_atom_head_nonstring array_access_expr %type set_expr string_expr string_quote_rest annotation_expr %type simple_array_literal simple_array_literal_2d simple_array_comp if_then_else_expr call_expr quoted_op_call let_expr operation_item_tail set_literal set_comp %type expr_list expr_list_head array_access_expr_list array_access_expr_list_head elseif_list let_vardecl_item_list enum_id_list string_lit_list %type simple_array_literal_2d_list array_access_tail %type simple_array_literal_3d_list %type comp_tail %type generator generator_eq %type generator_list generator_list_head %type id_list id_list_head %type comp_or_expr comp_or_expr_head %type annotations ne_annotations %type quoted_op %type id_or_quoted_op %type opt_opt %% /********************************/ /* main goal and item lists */ /********************************/ model : item_list item_list : /* empty */ | item_list_head semi_or_none item_list_head: item { ParserState* pp = static_cast(parm); if ($1) { pp->model->addItem($1); GC::unlock(); GC::lock(); } } | doc_file_comments item { ParserState* pp = static_cast(parm); if ($2) { pp->model->addItem($2); GC::unlock(); GC::lock(); } } | item_list_head ';' item { ParserState* pp = static_cast(parm); if ($3) { pp->model->addItem($3); GC::unlock(); GC::lock(); } } | item_list_head ';' doc_file_comments item { ParserState* pp = static_cast(parm); if ($4) { pp->model->addItem($4); GC::unlock(); GC::lock(); } } | item error_item_start { yyerror(&@2, parm, "unexpected item, expecting ';' or end of file"); YYERROR; } | error ';' item doc_file_comments: MZN_DOC_FILE_COMMENT { ParserState* pp = static_cast(parm); if (pp->parseDocComments && $1) { pp->model->addDocComment($1); } free($1); } | doc_file_comments MZN_DOC_FILE_COMMENT { ParserState* pp = static_cast(parm); if (pp->parseDocComments && $2) { pp->model->addDocComment($2); } free($2); } semi_or_none : | ';' item : MZN_DOC_COMMENT item_tail { $$ = $2; ParserState* pp = static_cast(parm); if (FunctionI* fi = Item::dyn_cast($$)) { if (pp->parseDocComments) { fi->ann().add(createDocComment(@1,$1)); } } else if (VarDeclI* vdi = Item::dyn_cast($$)) { if (pp->parseDocComments) { vdi->e()->addAnnotation(createDocComment(@1,$1)); } } else { yyerror(&@2, parm, "documentation comments are only supported for function, predicate and variable declarations"); } free($1); } | item_tail { $$ = $1; } item_tail : include_item { $$=notInDatafile(&@$,parm,"include") ? $1 : NULL; } | vardecl_item { $$=notInDatafile(&@$,parm,"variable declaration") ? $1 : NULL; } | assign_item | constraint_item { $$=notInDatafile(&@$,parm,"constraint") ? $1 : NULL; } | solve_item { $$=notInDatafile(&@$,parm,"solve") ? $1 : NULL; } | output_item { $$=notInDatafile(&@$,parm,"output") ? $1 : NULL; } | predicate_item { $$=notInDatafile(&@$,parm,"predicate") ? $1 : NULL; } | function_item { $$=notInDatafile(&@$,parm,"predicate") ? $1 : NULL; } | annotation_item { $$=notInDatafile(&@$,parm,"annotation") ? $1 : NULL; } error_item_start : MZN_INCLUDE | MZN_ENUM | MZN_OUTPUT | MZN_CONSTRAINT | MZN_SOLVE | MZN_PREDICATE | MZN_FUNCTION | MZN_TEST | MZN_ANNOTATION include_item : MZN_INCLUDE MZN_STRING_LITERAL { ParserState* pp = static_cast(parm); map::iterator ret = pp->seenModels.find($2); IncludeI* ii = new IncludeI(@$,ASTString($2)); $$ = ii; if (ret == pp->seenModels.end()) { Model* im = new Model; im->setParent(pp->model); im->setFilename($2); string fpath = FileUtils::dir_name(pp->filename); string fbase = FileUtils::base_name(pp->filename); if (fpath=="") fpath="./"; ParseWorkItem pm(im, ii, fpath, $2); pp->files.push_back(pm); ii->m(im); pp->seenModels.insert(pair($2,im)); } else { ii->m(ret->second, false); } free($2); } vardecl_item : ti_expr_and_id annotations { if ($1 && $2) $1->addAnnotations(*$2); if ($1) $$ = new VarDeclI(@$,$1); delete $2; } | ti_expr_and_id annotations MZN_EQ expr { if ($1) $1->e($4); if ($1 && $2) $1->addAnnotations(*$2); if ($1) $$ = new VarDeclI(@$,$1); delete $2; } | MZN_ENUM MZN_IDENTIFIER { TypeInst* ti = new TypeInst(@$,Type::parsetint()); ti->setIsEnum(true); VarDecl* vd = new VarDecl(@$,ti,$2); free($2); $$ = new VarDeclI(@$,vd); } | MZN_ENUM MZN_IDENTIFIER MZN_EQ '{' enum_id_list '}' { TypeInst* ti = new TypeInst(@$,Type::parsetint()); ti->setIsEnum(true); SetLit* sl = new SetLit(@$, *$5); VarDecl* vd = new VarDecl(@$,ti,$2,sl); free($2); delete $5; $$ = new VarDeclI(@$,vd); } | MZN_ENUM MZN_IDENTIFIER MZN_EQ MZN_LEFT_BRACKET string_lit_list MZN_RIGHT_BRACKET { TypeInst* ti = new TypeInst(@$,Type::parsetint()); ti->setIsEnum(true); vector args; args.push_back(new ArrayLit(@$,*$5)); Call* sl = new Call(@$, constants().ids.anonEnumFromStrings, args); VarDecl* vd = new VarDecl(@$,ti,$2,sl); free($2); delete $5; $$ = new VarDeclI(@$,vd); } | MZN_ENUM MZN_IDENTIFIER MZN_EQ MZN_IDENTIFIER '(' expr ')' { TypeInst* ti = new TypeInst(@$,Type::parsetint()); ti->setIsEnum(true); vector args; args.push_back($6); Call* sl = new Call(@$, ASTString($4), args); VarDecl* vd = new VarDecl(@$,ti,$2,sl); free($2); free($4); $$ = new VarDeclI(@$,vd); } string_lit_list : // empty { $$ = new std::vector(); } | MZN_STRING_LITERAL { $$ = new std::vector(); $$->push_back(new StringLit(@$, $1)); free($1); } | string_lit_list ',' MZN_STRING_LITERAL { $$ = $1; if ($$) $$->push_back(new StringLit(@$, $3)); free($3); } enum_id_list : // empty { $$ = new std::vector(); } | MZN_IDENTIFIER { $$ = new std::vector(); $$->push_back(new Id(@$,$1,NULL)); free($1); } | enum_id_list ',' MZN_IDENTIFIER { $$ = $1; if ($$) $$->push_back(new Id(@$,$3,NULL)); free($3); } assign_item : MZN_IDENTIFIER MZN_EQ expr { $$ = new AssignI(@$,$1,$3); free($1); } constraint_item : MZN_CONSTRAINT expr { $$ = new ConstraintI(@$,$2);} | MZN_CONSTRAINT MZN_COLONCOLON string_expr expr { $$ = new ConstraintI(@$,$4); if ($4 && $3) $$->cast()->e()->ann().add(new Call(@2, ASTString("mzn_constraint_name"), {$3})); } solve_item : MZN_SOLVE annotations MZN_SATISFY { $$ = SolveI::sat(@$); if ($$ && $2) $$->cast()->ann().add(*$2); delete $2; } | MZN_SOLVE annotations MZN_MINIMIZE expr { $$ = SolveI::min(@$,$4); if ($$ && $2) $$->cast()->ann().add(*$2); delete $2; } | MZN_SOLVE annotations MZN_MAXIMIZE expr { $$ = SolveI::max(@$,$4); if ($$ && $2) $$->cast()->ann().add(*$2); delete $2; } output_item : MZN_OUTPUT expr { $$ = new OutputI(@$,$2);} predicate_item : MZN_PREDICATE MZN_IDENTIFIER params annotations operation_item_tail { if ($3) $$ = new FunctionI(@$,$2,new TypeInst(@$, Type::varbool()),*$3,$5); if ($$ && $4) $$->cast()->ann().add(*$4); free($2); delete $3; delete $4; } | MZN_TEST MZN_IDENTIFIER params annotations operation_item_tail { if ($3) $$ = new FunctionI(@$,$2,new TypeInst(@$, Type::parbool()),*$3,$5); if ($$ && $4) $$->cast()->ann().add(*$4); free($2); delete $3; delete $4; } function_item : MZN_FUNCTION ti_expr ':' id_or_quoted_op params annotations operation_item_tail { if ($5) $$ = new FunctionI(@$,$4,$2,*$5,$7); if ($$ && $6) $$->cast()->ann().add(*$6); free($4); delete $5; delete $6; } | ti_expr ':' MZN_IDENTIFIER '(' params_list ')' annotations operation_item_tail { if ($5) $$ = new FunctionI(@$,$3,$1,*$5,$8); if ($$ && $7) $$->cast()->ann().add(*$7); free($3); delete $5; delete $7; } annotation_item : MZN_ANNOTATION MZN_IDENTIFIER params { TypeInst* ti=new TypeInst(@1,Type::ann()); if ($3==NULL || $3->empty()) { VarDecl* vd = new VarDecl(@$,ti,$2); $$ = new VarDeclI(@$,vd); } else { $$ = new FunctionI(@$,$2,ti,*$3,NULL); } free($2); delete $3; } | MZN_ANNOTATION MZN_IDENTIFIER params MZN_EQ expr { TypeInst* ti=new TypeInst(@1,Type::ann()); if ($3) $$ = new FunctionI(@$,$2,ti,*$3,$5); delete $3; } operation_item_tail : /*empty*/ { $$=NULL; } | MZN_EQ expr { $$=$2; } params : /* empty */ { $$=new vector(); } | '(' params_list ')' { $$=$2; } | '(' error ')' { $$=new vector(); } params_list : /* empty */ { $$=new vector(); } | params_list_head comma_or_none { $$=$1; } params_list_head : ti_expr_and_id_or_anon { $$=new vector(); if ($1) $1->toplevel(false); if ($1) $$->push_back($1); } | params_list_head ',' ti_expr_and_id_or_anon { $$=$1; if ($3) $3->toplevel(false); if ($1 && $3) $1->push_back($3); } comma_or_none : | ',' ti_expr_and_id_or_anon : ti_expr_and_id { $$=$1; } | ti_expr { if ($1) $$=new VarDecl(@$, $1, ""); } ti_expr_and_id : ti_expr ':' MZN_IDENTIFIER { if ($1 && $3) $$ = new VarDecl(@$, $1, $3); free($3); } ti_expr_list : ti_expr_list_head comma_or_none { $$=$1; } ti_expr_list_head : ti_expr { $$=new vector(); $$->push_back($1); } | ti_expr_list_head ',' ti_expr { $$=$1; if ($1 && $3) $1->push_back($3); } ti_expr : base_ti_expr | MZN_ARRAY MZN_LEFT_BRACKET ti_expr_list MZN_RIGHT_BRACKET MZN_OF base_ti_expr { $$ = $6; if ($$ && $3) $$->setRanges(*$3); delete $3; } | MZN_LIST MZN_OF base_ti_expr { $$ = $3; std::vector ti(1); ti[0] = new TypeInst(@$,Type::parint()); if ($$) $$->setRanges(ti); } base_ti_expr : base_ti_expr_tail { $$ = $1; } | MZN_OPT base_ti_expr_tail { $$ = $2; if ($$) { Type tt = $$->type(); tt.ot(Type::OT_OPTIONAL); $$->type(tt); } } | MZN_PAR opt_opt base_ti_expr_tail { $$ = $3; if ($$ && $2) { Type tt = $$->type(); tt.ot(Type::OT_OPTIONAL); $$->type(tt); } } | MZN_VAR opt_opt base_ti_expr_tail { $$ = $3; if ($$) { Type tt = $$->type(); tt.ti(Type::TI_VAR); if ($2) tt.ot(Type::OT_OPTIONAL); $$->type(tt); } } | opt_opt MZN_SET MZN_OF base_ti_expr_tail { $$ = $4; if ($$) { Type tt = $$->type(); tt.st(Type::ST_SET); if ($1) tt.ot(Type::OT_OPTIONAL); $$->type(tt); } } | MZN_PAR opt_opt MZN_SET MZN_OF base_ti_expr_tail { $$ = $5; if ($$) { Type tt = $$->type(); tt.st(Type::ST_SET); if ($2) tt.ot(Type::OT_OPTIONAL); $$->type(tt); } } | MZN_VAR opt_opt MZN_SET MZN_OF base_ti_expr_tail { $$ = $5; if ($$) { Type tt = $$->type(); tt.ti(Type::TI_VAR); tt.st(Type::ST_SET); if ($2) tt.ot(Type::OT_OPTIONAL); $$->type(tt); } } opt_opt: /* nothing */ { $$ = false; } | MZN_OPT { $$ = true; } base_ti_expr_tail : MZN_INT { $$ = new TypeInst(@$,Type::parint()); } | MZN_BOOL { $$ = new TypeInst(@$,Type::parbool()); } | MZN_FLOAT { $$ = new TypeInst(@$,Type::parfloat()); } | MZN_STRING { $$ = new TypeInst(@$,Type::parstring()); } | MZN_ANN { $$ = new TypeInst(@$,Type::ann()); } | set_expr { if ($1) $$ = new TypeInst(@$,Type(),$1); } | MZN_TI_IDENTIFIER { $$ = new TypeInst(@$,Type::top(), new TIId(@$, $1)); free($1); } | MZN_TI_ENUM_IDENTIFIER { $$ = new TypeInst(@$,Type::parint(), new TIId(@$, $1)); free($1); } array_access_expr_list : array_access_expr_list_head comma_or_none array_access_expr_list_head : array_access_expr { $$=new std::vector; $$->push_back($1); } | array_access_expr_list_head ',' array_access_expr { $$=$1; if ($$ && $3) $$->push_back($3); } array_access_expr : expr { $$ = $1; } | MZN_DOTDOT { $$=new SetLit(@$, IntSetVal::a(-IntVal::infinity(),IntVal::infinity())); } | MZN_DOTDOT expr { if ($2==NULL) { $$ = NULL; } else if ($2->isa()) { $$=new SetLit(@$, IntSetVal::a(-IntVal::infinity(),$2->cast()->v())); } else { $$=new BinOp(@$, IntLit::a(-IntVal::infinity()), BOT_DOTDOT, $2); } } | expr MZN_DOTDOT { if ($1==NULL) { $$ = NULL; } else if ($1->isa()) { $$=new SetLit(@$, IntSetVal::a($1->cast()->v(),IntVal::infinity())); } else { $$=new BinOp(@$, $1, BOT_DOTDOT, IntLit::a(IntVal::infinity())); } } expr_list : expr_list_head comma_or_none expr_list_head : expr { $$=new std::vector; $$->push_back($1); } | expr_list_head ',' expr { $$=$1; if ($$ && $3) $$->push_back($3); } /// set_expr : expr_atom_head | set_expr MZN_COLONCOLON annotation_expr { if ($1 && $3) $1->addAnnotation($3); $$=$1; } | set_expr MZN_UNION set_expr { $$=new BinOp(@$, $1, BOT_UNION, $3); } | set_expr MZN_DIFF set_expr { $$=new BinOp(@$, $1, BOT_DIFF, $3); } | set_expr MZN_SYMDIFF set_expr { $$=new BinOp(@$, $1, BOT_SYMDIFF, $3); } | set_expr MZN_DOTDOT set_expr { if ($1==NULL || $3==NULL) { $$ = NULL; } else if ($1->isa() && $3->isa()) { $$=new SetLit(@$, IntSetVal::a($1->cast()->v(),$3->cast()->v())); } else { $$=new BinOp(@$, $1, BOT_DOTDOT, $3); } } | MZN_DOTDOT_QUOTED '(' expr ',' expr ')' { if ($3==NULL || $5==NULL) { $$ = NULL; } else if ($3->isa() && $5->isa()) { $$=new SetLit(@$, IntSetVal::a($3->cast()->v(),$5->cast()->v())); } else { $$=new BinOp(@$, $3, BOT_DOTDOT, $5); } } | set_expr MZN_INTERSECT set_expr { $$=new BinOp(@$, $1, BOT_INTERSECT, $3); } | set_expr MZN_PLUSPLUS set_expr { $$=new BinOp(@$, $1, BOT_PLUSPLUS, $3); } | set_expr MZN_PLUS set_expr { $$=new BinOp(@$, $1, BOT_PLUS, $3); } | set_expr MZN_MINUS set_expr { $$=new BinOp(@$, $1, BOT_MINUS, $3); } | set_expr MZN_MULT set_expr { $$=new BinOp(@$, $1, BOT_MULT, $3); } | set_expr MZN_DIV set_expr { $$=new BinOp(@$, $1, BOT_DIV, $3); } | set_expr MZN_IDIV set_expr { $$=new BinOp(@$, $1, BOT_IDIV, $3); } | set_expr MZN_MOD set_expr { $$=new BinOp(@$, $1, BOT_MOD, $3); } | set_expr MZN_POW set_expr { $$=new BinOp(@$, $1, BOT_POW, $3); } | set_expr MZN_WEAK_PLUS set_expr { vector args; args.push_back($1); args.push_back($3); $$=new Call(@$, ASTString("~+"), args); } | set_expr MZN_WEAK_MINUS set_expr { vector args; args.push_back($1); args.push_back($3); $$=new Call(@$, ASTString("~-"), args); } | set_expr MZN_WEAK_MULT set_expr { vector args; args.push_back($1); args.push_back($3); $$=new Call(@$, ASTString("~*"), args); } | set_expr MZN_WEAK_EQ set_expr { vector args; args.push_back($1); args.push_back($3); $$=new Call(@$, ASTString("~="), args); } | set_expr MZN_QUOTED_IDENTIFIER set_expr { vector args; args.push_back($1); args.push_back($3); $$=new Call(@$, $2, args); free($2); } | MZN_PLUS set_expr %prec MZN_NOT { $$=new UnOp(@$, UOT_PLUS, $2); } | MZN_MINUS set_expr %prec MZN_NOT { if ($2 && $2->isa()) { $$ = IntLit::a(-$2->cast()->v()); } else if ($2 && $2->isa()) { $$ = FloatLit::a(-$2->cast()->v()); } else { $$=new UnOp(@$, UOT_MINUS, $2); } } /// expr : expr_atom_head | expr MZN_COLONCOLON annotation_expr { if ($1 && $3) $1->addAnnotation($3); $$=$1; } | expr MZN_EQUIV expr { $$=new BinOp(@$, $1, BOT_EQUIV, $3); } | expr MZN_IMPL expr { $$=new BinOp(@$, $1, BOT_IMPL, $3); } | expr MZN_RIMPL expr { $$=new BinOp(@$, $1, BOT_RIMPL, $3); } | expr MZN_OR expr { $$=new BinOp(@$, $1, BOT_OR, $3); } | expr MZN_XOR expr { $$=new BinOp(@$, $1, BOT_XOR, $3); } | expr MZN_AND expr { $$=new BinOp(@$, $1, BOT_AND, $3); } | expr MZN_LE expr { $$=new BinOp(@$, $1, BOT_LE, $3); } | expr MZN_GR expr { $$=new BinOp(@$, $1, BOT_GR, $3); } | expr MZN_LQ expr { $$=new BinOp(@$, $1, BOT_LQ, $3); } | expr MZN_GQ expr { $$=new BinOp(@$, $1, BOT_GQ, $3); } | expr MZN_EQ expr { $$=new BinOp(@$, $1, BOT_EQ, $3); } | expr MZN_NQ expr { $$=new BinOp(@$, $1, BOT_NQ, $3); } | expr MZN_IN expr { $$=new BinOp(@$, $1, BOT_IN, $3); } | expr MZN_SUBSET expr { $$=new BinOp(@$, $1, BOT_SUBSET, $3); } | expr MZN_SUPERSET expr { $$=new BinOp(@$, $1, BOT_SUPERSET, $3); } | expr MZN_UNION expr { $$=new BinOp(@$, $1, BOT_UNION, $3); } | expr MZN_DIFF expr { $$=new BinOp(@$, $1, BOT_DIFF, $3); } | expr MZN_SYMDIFF expr { $$=new BinOp(@$, $1, BOT_SYMDIFF, $3); } | expr MZN_DOTDOT expr { if ($1==NULL || $3==NULL) { $$ = NULL; } else if ($1->isa() && $3->isa()) { $$=new SetLit(@$, IntSetVal::a($1->cast()->v(),$3->cast()->v())); } else { $$=new BinOp(@$, $1, BOT_DOTDOT, $3); } } | MZN_DOTDOT_QUOTED '(' expr ',' expr ')' { if ($3==NULL || $5==NULL) { $$ = NULL; } else if ($3->isa() && $5->isa()) { $$=new SetLit(@$, IntSetVal::a($3->cast()->v(),$5->cast()->v())); } else { $$=new BinOp(@$, $3, BOT_DOTDOT, $5); } } | expr MZN_INTERSECT expr { $$=new BinOp(@$, $1, BOT_INTERSECT, $3); } | expr MZN_PLUSPLUS expr { $$=new BinOp(@$, $1, BOT_PLUSPLUS, $3); } | expr MZN_PLUS expr { $$=new BinOp(@$, $1, BOT_PLUS, $3); } | expr MZN_MINUS expr { $$=new BinOp(@$, $1, BOT_MINUS, $3); } | expr MZN_MULT expr { $$=new BinOp(@$, $1, BOT_MULT, $3); } | expr MZN_DIV expr { $$=new BinOp(@$, $1, BOT_DIV, $3); } | expr MZN_IDIV expr { $$=new BinOp(@$, $1, BOT_IDIV, $3); } | expr MZN_MOD expr { $$=new BinOp(@$, $1, BOT_MOD, $3); } | expr MZN_POW expr { $$=new BinOp(@$, $1, BOT_POW, $3); } | expr MZN_WEAK_PLUS expr { vector args; args.push_back($1); args.push_back($3); $$=new Call(@$, ASTString("~+"), args); } | expr MZN_WEAK_MINUS expr { vector args; args.push_back($1); args.push_back($3); $$=new Call(@$, ASTString("~-"), args); } | expr MZN_WEAK_MULT expr { vector args; args.push_back($1); args.push_back($3); $$=new Call(@$, ASTString("~*"), args); } | expr MZN_WEAK_EQ expr { vector args; args.push_back($1); args.push_back($3); $$=new Call(@$, ASTString("~="), args); } | expr MZN_QUOTED_IDENTIFIER expr { vector args; args.push_back($1); args.push_back($3); $$=new Call(@$, $2, args); free($2); } | MZN_NOT expr %prec MZN_NOT { $$=new UnOp(@$, UOT_NOT, $2); } | MZN_PLUS expr %prec MZN_NOT { if (($2 && $2->isa()) || ($2 && $2->isa())) { $$ = $2; } else { $$=new UnOp(@$, UOT_PLUS, $2); } } | MZN_MINUS expr %prec MZN_NOT { if ($2 && $2->isa()) { $$ = IntLit::a(-$2->cast()->v()); } else if ($2 && $2->isa()) { $$ = FloatLit::a(-$2->cast()->v()); } else { $$=new UnOp(@$, UOT_MINUS, $2); } } expr_atom_head : expr_atom_head_nonstring { $$=$1; } | string_expr { $$=$1; } expr_atom_head_nonstring : '(' expr ')' { $$=$2; } | '(' expr ')' array_access_tail { if ($4) $$=createArrayAccess(@$, $2, *$4); delete $4; } | MZN_IDENTIFIER { $$=new Id(@$, $1, NULL); free($1); } | MZN_IDENTIFIER array_access_tail { if ($2) $$=createArrayAccess(@$, new Id(@1,$1,NULL), *$2); free($1); delete $2; } | MZN_UNDERSCORE { $$=new AnonVar(@$); } | MZN_UNDERSCORE array_access_tail { if ($2) $$=createArrayAccess(@$, new AnonVar(@$), *$2); delete $2; } | MZN_BOOL_LITERAL { $$=constants().boollit(($1!=0)); } | MZN_INTEGER_LITERAL { $$=IntLit::a($1); } | MZN_INFINITY { $$=IntLit::a(IntVal::infinity()); } | MZN_FLOAT_LITERAL { $$=FloatLit::a($1); } | MZN_ABSENT { $$=constants().absent; } | set_literal | set_literal array_access_tail { if ($2) $$=createArrayAccess(@$, $1, *$2); delete $2; } | set_comp | set_comp array_access_tail { if ($2) $$=createArrayAccess(@$, $1, *$2); delete $2; } | simple_array_literal | simple_array_literal array_access_tail { if ($2) $$=createArrayAccess(@$, $1, *$2); delete $2; } | simple_array_literal_2d | simple_array_literal_2d array_access_tail { if ($2) $$=createArrayAccess(@$, $1, *$2); delete $2; } | simple_array_comp | simple_array_comp array_access_tail { if ($2) $$=createArrayAccess(@$, $1, *$2); delete $2; } | if_then_else_expr | if_then_else_expr array_access_tail { if ($2) $$=createArrayAccess(@$, $1, *$2); delete $2; } | let_expr | call_expr | call_expr array_access_tail { if ($2) $$=createArrayAccess(@$, $1, *$2); delete $2; } string_expr: MZN_STRING_LITERAL { $$=new StringLit(@$, $1); free($1); } | MZN_STRING_QUOTE_START string_quote_rest { $$=new BinOp(@$, new StringLit(@$, $1), BOT_PLUSPLUS, $2); free($1); } string_quote_rest: expr_list_head MZN_STRING_QUOTE_END { if ($1) $$=new BinOp(@$, new Call(@$, ASTString("format"), *$1), BOT_PLUSPLUS, new StringLit(@$,$2)); free($2); delete $1; } | expr_list_head MZN_STRING_QUOTE_MID string_quote_rest { if ($1) $$=new BinOp(@$, new Call(@$, ASTString("format"), *$1), BOT_PLUSPLUS, new BinOp(@$, new StringLit(@$,$2), BOT_PLUSPLUS, $3)); free($2); delete $1; } array_access_tail : MZN_LEFT_BRACKET array_access_expr_list MZN_RIGHT_BRACKET { $$=new std::vector >(); if ($2) { $$->push_back(*$2); delete $2; } } | array_access_tail MZN_LEFT_BRACKET array_access_expr_list MZN_RIGHT_BRACKET { $$=$1; if ($$ && $3) { $$->push_back(*$3); delete $3; } } set_literal : '{' '}' { $$ = new SetLit(@$, std::vector()); } | '{' expr_list '}' { if ($2) $$ = new SetLit(@$, *$2); delete $2; } set_comp : '{' expr '|' comp_tail '}' { if ($4) $$ = new Comprehension(@$, $2, *$4, true); delete $4; } comp_tail : generator_list { if ($1) $$=new Generators; $$->_g = *$1; delete $1; } generator_list : generator_list_head comma_or_none generator_list_head : generator { $$=new std::vector; if ($1) $$->push_back(*$1); delete $1; } | generator_eq { $$=new std::vector; if ($1) $$->push_back(*$1); delete $1; } | generator_eq MZN_WHERE expr { $$=new std::vector; if ($1) $$->push_back(*$1); if ($1 && $3) $$->push_back(Generator($$->size(),$3)); delete $1; } | generator_list_head ',' generator { $$=$1; if ($$ && $3) $$->push_back(*$3); delete $3; } | generator_list_head ',' generator_eq { $$=$1; if ($$ && $3) $$->push_back(*$3); delete $3; } | generator_list_head ',' generator_eq MZN_WHERE expr { $$=$1; if ($$ && $3) $$->push_back(*$3); if ($$ && $3 && $5) $$->push_back(Generator($$->size(),$5)); delete $3; } generator : id_list MZN_IN expr { if ($1 && $3) $$=new Generator(*$1,$3,NULL); else $$=NULL; delete $1; } | id_list MZN_IN expr MZN_WHERE expr { if ($1 && $3) $$=new Generator(*$1,$3,$5); else $$=NULL; delete $1; } generator_eq : MZN_IDENTIFIER MZN_EQ expr { if ($3) $$=new Generator({$1},NULL,$3); else $$=NULL; free($1); } id_list : id_list_head comma_or_none id_list_head : MZN_IDENTIFIER { $$=new std::vector; $$->push_back($1); free($1); } | id_list_head ',' MZN_IDENTIFIER { $$=$1; if ($$ && $3) $$->push_back($3); free($3); } simple_array_literal : MZN_LEFT_BRACKET MZN_RIGHT_BRACKET { $$=new ArrayLit(@$, std::vector()); } | MZN_LEFT_BRACKET expr_list MZN_RIGHT_BRACKET { if ($2) $$=new ArrayLit(@$, *$2); delete $2; } simple_array_literal_2d : MZN_LEFT_2D_BRACKET MZN_RIGHT_2D_BRACKET { $$=new ArrayLit(@$, std::vector >()); } | MZN_LEFT_2D_BRACKET simple_array_literal_2d_list MZN_RIGHT_2D_BRACKET { if ($2) { $$=new ArrayLit(@$, *$2); for (unsigned int i=1; i<$2->size(); i++) if ((*$2)[i].size() != (*$2)[i-1].size()) yyerror(&@2, parm, "syntax error, all sub-arrays of 2d array literal must have the same length"); delete $2; } else { $$ = NULL; } } | MZN_LEFT_2D_BRACKET simple_array_literal_2d_list '|' MZN_RIGHT_2D_BRACKET { if ($2) { $$=new ArrayLit(@$, *$2); for (unsigned int i=1; i<$2->size(); i++) if ((*$2)[i].size() != (*$2)[i-1].size()) yyerror(&@2, parm, "syntax error, all sub-arrays of 2d array literal must have the same length"); delete $2; } else { $$ = NULL; } } | MZN_LEFT_2D_BRACKET simple_array_literal_3d_list MZN_RIGHT_2D_BRACKET { if ($2) { std::vector > dims(3); dims[0] = std::pair(1,static_cast($2->size())); if ($2->size()==0) { dims[1] = std::pair(1,0); dims[2] = std::pair(1,0); } else { dims[1] = std::pair(1,static_cast((*$2)[0].size())); if ((*$2)[0].size()==0) { dims[2] = std::pair(1,0); } else { dims[2] = std::pair(1,static_cast((*$2)[0][0].size())); } } std::vector a; for (int i=0; i > >; } | '|' simple_array_literal_2d_list '|' { $$=new std::vector > >; if ($2) $$->push_back(*$2); delete $2; } | simple_array_literal_3d_list ',' '|' simple_array_literal_2d_list '|' { $$=$1; if ($$ && $4) $$->push_back(*$4); delete $4; } simple_array_literal_2d_list : expr_list { $$=new std::vector >; if ($1) $$->push_back(*$1); delete $1; } | simple_array_literal_2d_list '|' expr_list { $$=$1; if ($$ && $3) $$->push_back(*$3); delete $3; } simple_array_comp : MZN_LEFT_BRACKET expr '|' comp_tail MZN_RIGHT_BRACKET { if ($4) $$=new Comprehension(@$, $2, *$4, false); delete $4; } if_then_else_expr : MZN_IF expr MZN_THEN expr MZN_ENDIF { std::vector iexps; iexps.push_back($2); iexps.push_back($4); $$=new ITE(@$, iexps, NULL); } | MZN_IF expr MZN_THEN expr elseif_list MZN_ELSE expr MZN_ENDIF { std::vector iexps; iexps.push_back($2); iexps.push_back($4); if ($5) { for (unsigned int i=0; i<$5->size(); i+=2) { iexps.push_back((*$5)[i]); iexps.push_back((*$5)[i+1]); } } $$=new ITE(@$, iexps,$7); delete $5; } elseif_list : { $$=new std::vector; } | elseif_list MZN_ELSEIF expr MZN_THEN expr { $$=$1; if ($$ && $3 && $5) { $$->push_back($3); $$->push_back($5); } } quoted_op : MZN_EQUIV_QUOTED { $$=BOT_EQUIV; } | MZN_IMPL_QUOTED { $$=BOT_IMPL; } | MZN_RIMPL_QUOTED { $$=BOT_RIMPL; } | MZN_OR_QUOTED { $$=BOT_OR; } | MZN_XOR_QUOTED { $$=BOT_XOR; } | MZN_AND_QUOTED { $$=BOT_AND; } | MZN_LE_QUOTED { $$=BOT_LE; } | MZN_GR_QUOTED { $$=BOT_GR; } | MZN_LQ_QUOTED { $$=BOT_LQ; } | MZN_GQ_QUOTED { $$=BOT_GQ; } | MZN_EQ_QUOTED { $$=BOT_EQ; } | MZN_NQ_QUOTED { $$=BOT_NQ; } | MZN_IN_QUOTED { $$=BOT_IN; } | MZN_SUBSET_QUOTED { $$=BOT_SUBSET; } | MZN_SUPERSET_QUOTED { $$=BOT_SUPERSET; } | MZN_UNION_QUOTED { $$=BOT_UNION; } | MZN_DIFF_QUOTED { $$=BOT_DIFF; } | MZN_SYMDIFF_QUOTED { $$=BOT_SYMDIFF; } | MZN_PLUS_QUOTED { $$=BOT_PLUS; } | MZN_MINUS_QUOTED { $$=BOT_MINUS; } | MZN_MULT_QUOTED { $$=BOT_MULT; } | MZN_POW_QUOTED { $$=BOT_POW; } | MZN_DIV_QUOTED { $$=BOT_DIV; } | MZN_IDIV_QUOTED { $$=BOT_IDIV; } | MZN_MOD_QUOTED { $$=BOT_MOD; } | MZN_INTERSECT_QUOTED { $$=BOT_INTERSECT; } | MZN_PLUSPLUS_QUOTED { $$=BOT_PLUSPLUS; } | MZN_NOT_QUOTED { $$=-1; } quoted_op_call : quoted_op '(' expr ',' expr ')' { if ($1==-1) { $$=NULL; yyerror(&@3, parm, "syntax error, unary operator with two arguments"); } else { $$=new BinOp(@$, $3,static_cast($1),$5); } } | quoted_op '(' expr ')' { int uot=-1; switch ($1) { case -1: uot = UOT_NOT; break; case BOT_MINUS: uot = UOT_MINUS; break; case BOT_PLUS: uot = UOT_PLUS; break; default: yyerror(&@3, parm, "syntax error, binary operator with unary argument list"); break; } if (uot==-1) $$=NULL; else { if (uot==UOT_PLUS && $3 && ($3->isa() || $3->isa())) { $$ = $3; } else if (uot==UOT_MINUS && $3 && $3->isa()) { $$ = IntLit::a(-$3->cast()->v()); } else if (uot==UOT_MINUS && $3 && $3->isa()) { $$ = FloatLit::a(-$3->cast()->v()); } else { $$=new UnOp(@$, static_cast(uot),$3); } } } call_expr : MZN_IDENTIFIER '(' ')' { $$=new Call(@$, $1, std::vector()); free($1); } | quoted_op_call | MZN_IDENTIFIER '(' comp_or_expr ')' { if ($3!=NULL) { bool hadWhere = false; std::vector args; for (unsigned int i=0; i<$3->size(); i++) { if ((*$3)[i].second) { yyerror(&@3, parm, "syntax error, 'where' expression outside generator call"); hadWhere = true; $$=NULL; } args.push_back((*$3)[i].first); } if (!hadWhere) { $$=new Call(@$, $1, args); } } free($1); delete $3; } | MZN_IDENTIFIER '(' comp_or_expr ')' '(' expr ')' { vector gens; vector ids; if ($3) { for (unsigned int i=0; i<$3->size(); i++) { if (Id* id = Expression::dyn_cast((*$3)[i].first)) { if ((*$3)[i].second) { ParserLocation loc = (*$3)[i].second->loc().parserLocation(); yyerror(&loc, parm, "illegal where expression in generator call"); } ids.push_back(id); } else { if (BinOp* boe = Expression::dyn_cast((*$3)[i].first)) { if (boe->lhs() && boe->rhs()) { Id* id = Expression::dyn_cast(boe->lhs()); if (id && boe->op() == BOT_IN) { ids.push_back(id); gens.push_back(Generator(ids,boe->rhs(),(*$3)[i].second)); ids = vector(); } else if (id && boe->op() == BOT_EQ && ids.empty()) { ids.push_back(id); gens.push_back(Generator(ids,NULL,boe->rhs())); if ((*$3)[i].second) { gens.push_back(Generator(gens.size(),(*$3)[i].second)); } ids = vector(); } else { ParserLocation loc = (*$3)[i].first->loc().parserLocation(); yyerror(&loc, parm, "illegal expression in generator call"); } } } else { ParserLocation loc = (*$3)[i].first->loc().parserLocation(); yyerror(&loc, parm, "illegal expression in generator call"); } } } } if (ids.size() != 0) { yyerror(&@3, parm, "illegal expression in generator call"); } ParserState* pp = static_cast(parm); if (pp->hadError) { $$=NULL; } else { Generators g; g._g = gens; Comprehension* ac = new Comprehension(@$, $6,g,false); vector args; args.push_back(ac); $$=new Call(@$, $1, args); } free($1); delete $3; } comp_or_expr : comp_or_expr_head comma_or_none comp_or_expr_head : expr { $$=new vector >; if ($1) { $$->push_back(pair($1,NULL)); } } | expr MZN_WHERE expr { $$=new vector >; if ($1 && $3) { $$->push_back(pair($1,$3)); } } | comp_or_expr_head ',' expr { $$=$1; if ($$ && $3) $$->push_back(pair($3,NULL)); } | comp_or_expr_head ',' expr MZN_WHERE expr { $$=$1; if ($$ && $3 && $5) $$->push_back(pair($3,$5)); } let_expr : MZN_LET '{' let_vardecl_item_list '}' MZN_IN expr %prec PREC_ANNO { if ($3 && $6) { $$=new Let(@$, *$3, $6); delete $3; } else { $$=NULL; } } | MZN_LET '{' let_vardecl_item_list comma_or_semi '}' MZN_IN expr %prec PREC_ANNO { if ($3 && $7) { $$=new Let(@$, *$3, $7); delete $3; } else { $$=NULL; } } let_vardecl_item_list : let_vardecl_item { $$=new vector; $$->push_back($1); } | constraint_item { $$=new vector; if ($1) { ConstraintI* ce = $1->cast(); $$->push_back(ce->e()); ce->e(NULL); } } | let_vardecl_item_list comma_or_semi let_vardecl_item { $$=$1; if ($$ && $3) $$->push_back($3); } | let_vardecl_item_list comma_or_semi constraint_item { $$=$1; if ($$ && $3) { ConstraintI* ce = $3->cast(); $$->push_back(ce->e()); ce->e(NULL); } } comma_or_semi : ',' | ';' let_vardecl_item : ti_expr_and_id annotations { $$ = $1; if ($$) $$->toplevel(false); if ($$ && $2) $$->addAnnotations(*$2); delete $2; } | ti_expr_and_id annotations MZN_EQ expr { if ($1) $1->e($4); $$ = $1; if ($$) $$->loc(@$); if ($$) $$->toplevel(false); if ($$ && $2) $$->addAnnotations(*$2); delete $2; } annotations : /* empty */ { $$=NULL; } | ne_annotations annotation_expr : expr_atom_head_nonstring { $$ = $1; } | string_expr { $$ = new Call(@1, ASTString("mzn_expression_name"), {$1}); } ne_annotations : MZN_COLONCOLON annotation_expr { $$=new std::vector(1); (*$$)[0] = $2; } | ne_annotations MZN_COLONCOLON annotation_expr { $$=$1; if ($$) $$->push_back($3); } id_or_quoted_op : MZN_IDENTIFIER { $$=$1; } | MZN_EQUIV_QUOTED { $$=strdup("'<->'"); } | MZN_IMPL_QUOTED { $$=strdup("'->'"); } | MZN_RIMPL_QUOTED { $$=strdup("'<-'"); } | MZN_OR_QUOTED { $$=strdup("'\\/'"); } | MZN_XOR_QUOTED { $$=strdup("'xor'"); } | MZN_AND_QUOTED { $$=strdup("'/\\'"); } | MZN_LE_QUOTED { $$=strdup("'<'"); } | MZN_GR_QUOTED { $$=strdup("'>'"); } | MZN_LQ_QUOTED { $$=strdup("'<='"); } | MZN_GQ_QUOTED { $$=strdup("'>='"); } | MZN_EQ_QUOTED { $$=strdup("'='"); } | MZN_NQ_QUOTED { $$=strdup("'!='"); } | MZN_IN_QUOTED { $$=strdup("'in'"); } | MZN_SUBSET_QUOTED { $$=strdup("'subset'"); } | MZN_SUPERSET_QUOTED { $$=strdup("'superset'"); } | MZN_UNION_QUOTED { $$=strdup("'union'"); } | MZN_DIFF_QUOTED { $$=strdup("'diff'"); } | MZN_SYMDIFF_QUOTED { $$=strdup("'symdiff'"); } | MZN_DOTDOT_QUOTED { $$=strdup("'..'"); } | MZN_PLUS_QUOTED { $$=strdup("'+'"); } | MZN_MINUS_QUOTED { $$=strdup("'-'"); } | MZN_MULT_QUOTED { $$=strdup("'*'"); } | MZN_POW_QUOTED { $$=strdup("'^'"); } | MZN_DIV_QUOTED { $$=strdup("'/'"); } | MZN_IDIV_QUOTED { $$=strdup("'div'"); } | MZN_MOD_QUOTED { $$=strdup("'mod'"); } | MZN_INTERSECT_QUOTED { $$=strdup("'intersect'"); } | MZN_NOT_QUOTED { $$=strdup("'not'"); } | MZN_PLUSPLUS_QUOTED { $$=strdup("'++'"); } libminizinc-2.4.2/lib/passes/000077500000000000000000000000001360574160400161005ustar00rootroot00000000000000libminizinc-2.4.2/lib/passes/compile_pass.cpp000066400000000000000000000135311360574160400212650ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Kevin Leo */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace MiniZinc { using std::string; using std::vector; Env* changeLibrary(Env& e, vector& includePaths, string globals_dir, CompilePassFlags& compflags, bool verbose=false) { GCLock lock; CopyMap cm; Model* m = e.envi().orig_model ? e.envi().orig_model : e.envi().model; Model* new_mod = new Model(); new_mod->setFilename(m->filename().str()); new_mod->setFilepath(m->filepath().str()); vector new_includePaths; if(std::find(includePaths.begin(), includePaths.end(), globals_dir) == includePaths.end()) new_includePaths.push_back(globals_dir); new_includePaths.insert(new_includePaths.end(), includePaths.begin(), includePaths.end()); // Collect include items vector include_names; for(Item* item : *m) { if(IncludeI* inc = item->dyn_cast()) { include_names.push_back(inc->f().str()); } else { new_mod->addItem(copy(e.envi(),cm,item)); } } std::stringstream ss; for(auto& name : include_names) ss << "include \""<< name << "\";"; vector syntax_errors; Env* fenv = new Env(new_mod); //Model* inc_mod = parse(*fenv, include_names, {}, new_includePaths, true, true, verbose, std::cerr); Model* inc_mod = parseFromString(*fenv, ss.str(), m->filepath().str() + "_Dummy.mzn", new_includePaths, true, true, verbose, std::cerr, syntax_errors); if(inc_mod == nullptr) { for(const SyntaxError& se : syntax_errors) { std::cerr << std::endl; std::cerr << se.what() << ": " << se.msg() << std::endl; std::cerr << se.loc() << std::endl; } return nullptr; } IncludeI* new_inc = new IncludeI(Location().introduce(), string("MultiPassDummy.mzn")); new_inc->m(inc_mod); inc_mod->setParent(new_mod); new_mod->addItem(new_inc); return fenv; } CompilePass::CompilePass(Env* e, FlatteningOptions& opts, CompilePassFlags& cflags, string globals_library, vector include_paths, bool change_lib, bool ignore_unknown) : env(e), fopts(opts), compflags(cflags), library(globals_library), includePaths(include_paths), change_library(change_lib), ignore_unknown_ids(ignore_unknown) { } Env* CompilePass::run(Env* store, std::ostream& log) { Timer lasttime; if(compflags.verbose) log << "\n\tCompilePass: Flatten with \'" << library << "\' library ...\n"; Env* new_env; if(change_library) { new_env = changeLibrary(*env, includePaths, library, compflags, compflags.verbose); if(new_env == nullptr) return nullptr; new_env->envi().copyPathMapsAndState(store->envi()); } else { new_env = env; } new_env->envi().ignoreUnknownIds = ignore_unknown_ids; vector typeErrors; MiniZinc::typecheck(*new_env, new_env->model(), typeErrors, compflags.model_check_only || compflags.model_interface_only, compflags.allow_multi_assign); if (typeErrors.size() > 0) { std::ostringstream errstream; for (unsigned int i=0; idumpErrorStack(errstream); errstream << " " << e.msg() << std::endl; throw Error(errstream.str()); } if ( ! compflags.noMIPdomains ) { if (compflags.verbose) log << "MIP domains ..."; MIPdomains(*new_env, compflags.statistics); if (compflags.verbose) log << " done (" << lasttime.stoptime() << ")" << std::endl; } if (compflags.optimize) { if (compflags.verbose) log << "Optimizing ..."; optimize(*new_env, compflags.chain_compression); if (compflags.verbose) log << " done (" << lasttime.stoptime() << ")" << std::endl; } for (unsigned int i=0; iwarnings().size(); i++) { log << (compflags.werror ? "\n ERROR: " : "\n WARNING: ") << new_env->warnings()[i]; } if (compflags.werror && new_env->warnings().size() > 0) { throw Error("errors encountered"); } new_env->clearWarnings(); if (!compflags.newfzn) { if (compflags.verbose) log << "Converting to old FlatZinc ..."; oldflatzinc(*new_env); if (compflags.verbose) log << " done (" << lasttime.stoptime() << ")" << std::endl; } else { new_env->flat()->compact(); new_env->output()->compact(); } if(compflags.verbose) log << " done (" << lasttime.stoptime() << ")" << std::endl; return new_env; } CompilePass::~CompilePass() {}; } libminizinc-2.4.2/lib/passes/gecode_pass.cpp000066400000000000000000000015351360574160400210640ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Kevin Leo */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include namespace MiniZinc { GecodePass::GecodePass(GecodeOptions* g_opts) : gopts(g_opts) {} Env* GecodePass::run(Env* env, std::ostream& log) { try { GecodeSolverInstance gecode(*env,log,new GecodeOptions(*gopts)); gecode.processFlatZinc(); gecode.presolve(env->flat()); } catch(InternalError e) { std::cerr << "Warning during presolve: " << e.msg() << std::endl; } return env; } } libminizinc-2.4.2/lib/pathfileprinter.cpp000066400000000000000000000125401360574160400205100ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include namespace MiniZinc { using std::string; using std::vector; PathFilePrinter::PathFilePrinter(std::ostream& o, EnvI&) : os(o), constraint_index(0) {} void PathFilePrinter::addBetterName(Id* id, string name, string path, bool overwrite = false) { string oname; string opath; NameMap::iterator it = betternames.find(id); if(it != betternames.end()) { oname = it->second.first; opath = it->second.second; } if(!name.empty() && (overwrite || oname.empty())) oname = name; if(!path.empty() && (overwrite || opath.empty())) opath = path; betternames[id] = NamePair(oname, opath); } string path2name(string path) { std::stringstream name; size_t idpos = path.rfind("id:"); if(idpos != string::npos) { idpos += 3; size_t semi = path.find(";", idpos); if(semi != string::npos) { // Variable name name << path.substr(idpos, semi-idpos); // Check for array int dim = 0; size_t ilpos = semi-idpos; do { ilpos = path.find("il:", ilpos); if(ilpos != string::npos) { ilpos += 3; semi = path.find(";", ilpos); if(semi != string::npos) { if(dim == 0) name << "["; else name << ","; name << path.substr(ilpos, semi-ilpos); dim ++; } } } while(ilpos != string::npos); if(dim > 0) name << "?]"; // Check for anon if(path.find(":anon") != string::npos || path.find("=") != string::npos) { name.str(""); name.clear(); } } } return name.str(); } void PathFilePrinter::print(Model* m) { // Build map for(VarDeclIterator vdit = m->begin_vardecls(); vdit != m->end_vardecls(); ++vdit) { VarDecl* e = vdit->e(); for(ExpressionSetIter it = e->ann().begin(); it != e->ann().end(); ++it) { if(Call* ca = (*it)->dyn_cast()) { ASTString cid = ca->id(); if(cid == constants().ann.output_array) { if(ArrayLit* rhs = e->e()->dyn_cast()) { for(unsigned int ind=0; indsize(); ind++) { if(Id* id = (*rhs)[ind]->dyn_cast()) { std::stringstream bettername; bettername << *e->id() << "["; // Array of sets ArrayLit& dimsets = *ca->arg(0)->cast(); vector dims(dimsets.size(), 1); for(unsigned int i=0; icast(); dims[i] = sl->isv()->card(); } vector dimspan(dims.size(), 1); for(unsigned int i=0; icast()->isv()->min() + thisind << ","; } bettername << dimsets[dimsets.size()-1]->cast()->isv()->min() + curind << "]"; addBetterName(id, bettername.str(), "", true); } } } } else if(ca->id() == constants().ann.mzn_path) { StringLit* sl = ca->arg(0)->cast(); addBetterName(e->id(), path2name(sl->v().str()), sl->v().str()); } } } } // Print values for(Item* item : *m) print(item); } void PathFilePrinter::print(Item* item) { if(VarDeclI* vdi = item->dyn_cast()) { Id* id = vdi->e()->id(); NamePair np = betternames[id]; if(!np.first.empty() || !np.second.empty()) { // FlatZinc name os << *id << "\t"; // Nice name if(np.first.empty()) { os << *id << "\t"; } else { string name = np.first; os << name; if(name.find("?") != string::npos) os <<"(" << *id << ")"; os << "\t"; } // Path os << np.second << std::endl; } } else if (ConstraintI* ci = item->dyn_cast()) { StringLit* sl = nullptr; Expression* e = ci->e(); for(ExpressionSetIter it = e->ann().begin(); it != e->ann().end(); ++it) { if(Call* ca = (*it)->dyn_cast()) { ASTString cid = ca->id(); if(cid == constants().ann.mzn_path) { sl = ca->arg(0)->cast(); } } } os << constraint_index << "\t"; os << constraint_index << "\t"; if (sl) { os << sl->v(); } else { os << ""; } os << std::endl; constraint_index++; } } } libminizinc-2.4.2/lib/prettyprinter.cpp000066400000000000000000001646621360574160400202600ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Pierre Wilke * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include #include #include #include #include #include namespace MiniZinc { int precedence(const Expression* e) { if (const BinOp* bo = e->dyn_cast()) { switch (bo->op()) { case BOT_EQUIV: return 1200; case BOT_IMPL: return 1100; case BOT_RIMPL: return 1100; case BOT_OR: return 1000; case BOT_XOR: return 1000; case BOT_AND: return 900; case BOT_LE: return 800; case BOT_LQ: return 800; case BOT_GR: return 800; case BOT_GQ: return 800; case BOT_EQ: return 800; case BOT_NQ: return 800; case BOT_IN: return 700; case BOT_SUBSET: return 700; case BOT_SUPERSET: return 700; case BOT_UNION: return 600; case BOT_DIFF: return 600; case BOT_SYMDIFF: return 600; case BOT_DOTDOT: return 500; case BOT_PLUS: return 400; case BOT_MINUS: return 400; case BOT_MULT: return 300; case BOT_IDIV: return 300; case BOT_MOD: return 300; case BOT_DIV: return 300; case BOT_INTERSECT: return 300; case BOT_POW: return 200; case BOT_PLUSPLUS: return 200; default: assert(false); return -1; } } else if (e->isa()) { return 1300; } else { return 0; } } enum Assoc { AS_LEFT, AS_RIGHT, AS_NONE }; Assoc assoc(const BinOp* bo) { switch (bo->op()) { case BOT_LE: case BOT_LQ: case BOT_GR: case BOT_GQ: case BOT_NQ: case BOT_EQ: case BOT_IN: case BOT_SUBSET: case BOT_SUPERSET: case BOT_DOTDOT: return AS_NONE; case BOT_PLUSPLUS: return AS_RIGHT; default: return AS_LEFT; } } enum Parentheses { PN_LEFT = 1, PN_RIGHT = 2 }; Parentheses needParens(const BinOp* bo, const Expression* left, const Expression* right) { int pbo = precedence(bo); int pl = precedence(left); int pr = precedence(right); int ret = (pbo < pl) || (pbo == pl && assoc(bo) != AS_LEFT); ret += 2 * ((pbo < pr) || (pbo == pr && assoc(bo) != AS_RIGHT)); return static_cast(ret); } std::string Printer::escapeStringLit(const ASTString& s) { const char* sc = s.c_str(); std::ostringstream ret; for (unsigned int i=0; i::digits10+1); oss << fv; if (oss.str().find("e") == std::string::npos && oss.str().find(".") == std::string::npos) oss << ".0"; os << oss.str(); } } else { if (fv.isPlusInfinity()) os << "infinity"; else os << "-infinity"; } } class PlainPrinter { public: EnvI* env; std::ostream& os; bool _flatZinc; PlainPrinter(std::ostream& os0, bool flatZinc, EnvI* env0) : env(env0), os(os0), _flatZinc(flatZinc) {} void p(const Type& type, const Expression* e) { switch (type.ti()) { case Type::TI_PAR: break; case Type::TI_VAR: os << "var "; break; } if (type.ot()==Type::OT_OPTIONAL) os << "opt "; if (type.st()==Type::ST_SET) os << "set of "; if (e==NULL) { switch (type.bt()) { case Type::BT_INT: os << "int"; break; case Type::BT_BOOL: os << "bool"; break; case Type::BT_FLOAT: os << "float"; break; case Type::BT_STRING: os << "string"; break; case Type::BT_ANN: os << "ann"; break; case Type::BT_BOT: os << "bot"; break; case Type::BT_TOP: os << "top"; break; case Type::BT_UNKNOWN: os << "???"; break; } } else { p(e); } } void p(const Annotation& ann) { for (ExpressionSetIter it = ann.begin(); it != ann.end(); ++it) { os << ":: "; p(*it); } } void p(const Expression* e) { if (e==NULL) return; switch (e->eid()) { case Expression::E_INTLIT: os << e->cast()->v(); break; case Expression::E_FLOATLIT: { ppFloatVal(os, e->cast()->v()); } break; case Expression::E_SETLIT: { const SetLit& sl = *e->cast(); if (sl.isv()) { if (sl.isv()->size()==0) { os << (_flatZinc ? "1..0" : "{}"); } else if (sl.isv()->size()==1) { os << sl.isv()->min(0) << ".." << sl.isv()->max(0); } else { if (!sl.isv()->min(0).isFinite()) os << sl.isv()->min(0) << ".." << sl.isv()->max(0) << "++"; os << "{"; for (IntSetRanges isr(sl.isv()); isr();) { if (isr.min().isFinite() && isr.max().isFinite()) { for (IntVal i=isr.min(); i<=isr.max(); i++) { os << i; if (imax(sl.isv()->size()-1).isFinite()) os << "++" << sl.isv()->min(sl.isv()->size()-1) << ".." << sl.isv()->max(sl.isv()->size()-1); } } else if (sl.fsv()) { if (sl.fsv()->size()==0) { os << (_flatZinc ? "1.0..0.0" : "{}"); } else if (sl.fsv()->size()==1) { ppFloatVal(os, sl.fsv()->min(0)); os << ".."; ppFloatVal(os, sl.fsv()->max(0)); } else { bool allSingleton = true; for (FloatSetRanges isr(sl.fsv()); isr(); ++isr) { if (isr.min() != isr.max()) { allSingleton = false; break; } } if (allSingleton) { os << "{"; bool first = true; for (FloatSetRanges isr(sl.fsv()); isr(); ++isr) { if (!first) os << ","; first = false; ppFloatVal(os, isr.min()); } os << "}"; } else { bool first = true; for (FloatSetRanges isr(sl.fsv()); isr(); ++isr) { if (!first) os << "++"; first = false; ppFloatVal(os, isr.min()); os << ".."; ppFloatVal(os, isr.max()); } } } } else { os << "{"; for (unsigned int i = 0; i < sl.v().size(); i++) { p(sl.v()[i]); if (icast()->v() ? "true" : "false"); break; case Expression::E_STRINGLIT: os << "\"" << Printer::escapeStringLit(e->cast()->v()) << "\""; break; case Expression::E_ID: { if (e==constants().absent) { os << "<>"; } else { const Id* id = e->cast(); if(id->decl()) id = id->decl()->id(); if (id->idn() == -1) { os << id->v(); } else { os << "X_INTRODUCED_" << id->idn() << "_"; } } } break; case Expression::E_TIID: os << "$" << e->cast()->v(); break; case Expression::E_ANON: os << "_"; break; case Expression::E_ARRAYLIT: { const ArrayLit& al = *e->cast(); int n = al.dims(); if (n == 1 && al.min(0) == 1) { os << "["; for (unsigned int i = 0; i < al.size(); i++) { p(al[i]); if (icast(); p(aa.v()); os << "["; for (unsigned int i = 0; i < aa.idx().size(); i++) { p(aa.idx()[i]); if (icast(); os << (c.set() ? "{" : "["); p(c.e()); os << " | "; for (int i=0; iid()->v(); if (j < c.n_decls(i)-1) os << ","; } if (c.in(i)==NULL) { os << " = "; p(c.where(i)); } else { os << " in "; p(c.in(i)); if (c.where(i) != NULL) { os << " where "; p(c.where(i)); } } if (i < c.n_generators()) os << ", "; } os << (c.set() ? "}" : "]"); } break; case Expression::E_ITE: { const ITE& ite = *e->cast(); for (int i = 0; i < ite.size(); i++) { os << (i == 0 ? "if " : " elseif "); p(ite.e_if(i)); os << " then "; p(ite.e_then(i)); } os << " else "; p(ite.e_else()); os << " endif"; } break; case Expression::E_BINOP: { const BinOp& bo = *e->cast(); Parentheses ps = needParens(&bo, bo.lhs(), bo.rhs()); if (ps & PN_LEFT) os << "("; p(bo.lhs()); if (ps & PN_LEFT) os << ")"; switch (bo.op()) { case BOT_PLUS: os<<"+"; break; case BOT_MINUS: os<<"-"; break; case BOT_MULT: os<<"*"; break; case BOT_POW: os<<"^"; break; case BOT_DIV: os<<"/"; break; case BOT_IDIV: os<<" div "; break; case BOT_MOD: os<<" mod "; break; case BOT_LE: os<<" < "; break; case BOT_LQ: os<<"<="; break; case BOT_GR: os<<" > "; break; case BOT_GQ: os<<">="; break; case BOT_EQ: os<<"=="; break; case BOT_NQ: os<<"!="; break; case BOT_IN: os<<" in "; break; case BOT_SUBSET: os<<" subset "; break; case BOT_SUPERSET: os<<" superset "; break; case BOT_UNION: os<<" union "; break; case BOT_DIFF: os<<" diff "; break; case BOT_SYMDIFF: os<<" symdiff "; break; case BOT_INTERSECT: os<<" intersect "; break; case BOT_PLUSPLUS: os<<"++"; break; case BOT_EQUIV: os<<" <-> "; break; case BOT_IMPL: os<<" -> "; break; case BOT_RIMPL: os<<" <- "; break; case BOT_OR: os<<" \\/ "; break; case BOT_AND: os<<" /\\ "; break; case BOT_XOR: os<<" xor "; break; case BOT_DOTDOT: os<<".."; break; default: assert(false); break; } if (ps & PN_RIGHT) os << "("; p(bo.rhs()); if (ps & PN_RIGHT) os << ")"; } break; case Expression::E_UNOP: { const UnOp& uo = *e->cast(); switch (uo.op()) { case UOT_NOT: os << "not "; break; case UOT_PLUS: os << "+"; break; case UOT_MINUS: os << "-"; break; default: assert(false); break; } bool needParen = (uo.e()->isa() || uo.e()->isa() || !uo.ann().isEmpty()); if (needParen) os << "("; p(uo.e()); if (needParen) os << ")"; } break; case Expression::E_CALL: { const Call& c = *e->cast(); os << c.id() << "("; for (unsigned int i = 0; i < c.n_args(); i++) { p(c.arg(i)); if (i < c.n_args()-1) os << ","; } os << ")"; } break; case Expression::E_VARDECL: { const VarDecl& vd = *e->cast(); p(vd.ti()); if (!vd.ti()->isEnum()) { os << ":"; } if (vd.id()->idn() != -1) { os << " X_INTRODUCED_" << vd.id()->idn() << "_"; } else if (vd.id()->v().size() != 0) os << " " << vd.id()->v(); if (vd.introduced()) { os << " ::var_is_introduced "; } p(vd.ann()); if (vd.e()) { os << " = "; p(vd.e()); } } break; case Expression::E_LET: { const Let& l = *e->cast(); os << "let {"; for (unsigned int i = 0; i < l.let().size(); i++) { const Expression* li = l.let()[i]; if (!li->isa()) os << "constraint "; p(li); if (icast(); if (ti.isEnum()) { os << "enum"; } else if (env) { os << ti.type().toString(*env); } else { if (ti.isarray()) { os << "array ["; for (unsigned int i = 0; i < ti.ranges().size(); i++) { p(Type::parint(), ti.ranges()[i]); if (i < ti.ranges().size()-1) os << ","; } os << "] of "; } p(ti.type(),ti.domain()); } } } if (!e->isa()) { p(e->ann()); } } void p(const Item* i) { if (i==NULL) return; if (i->removed()) os << "% "; switch (i->iid()) { case Item::II_INC: os << "include \"" << i->cast()->f() << "\""; break; case Item::II_VD: p(i->cast()->e()); break; case Item::II_ASN: os << i->cast()->id() << " = "; p(i->cast()->e()); break; case Item::II_CON: os << "constraint "; p(i->cast()->e()); break; case Item::II_SOL: { const SolveI* si = i->cast(); os << "solve "; p(si->ann()); switch (si->st()) { case SolveI::ST_SAT: os << " satisfy"; break; case SolveI::ST_MIN: os << " minimize "; p(si->e()); break; case SolveI::ST_MAX: os << " maximize "; p(si->e()); break; } } break; case Item::II_OUT: os << "output "; p(i->cast()->e()); break; case Item::II_FUN: { const FunctionI& fi = *i->cast(); if (fi.ti()->type().isann() && fi.e() == NULL) { os << "annotation "; } else if (fi.ti()->type() == Type::parbool()) { os << "test "; } else if (fi.ti()->type() == Type::varbool()) { os << "predicate "; } else { os << "function "; p(fi.ti()); os << " : "; } os << fi.id(); if (fi.params().size() > 0) { os << "("; for (unsigned int i = 0; i < fi.params().size(); i++) { p(fi.params()[i]); if (i class ExpressionMapper { protected: T& _t; public: ExpressionMapper(T& t) : _t(t) { } typename T::ret map(const Expression* e) { switch (e->eid()) { case Expression::E_INTLIT: return _t.mapIntLit(*e->cast()); case Expression::E_FLOATLIT: return _t.mapFloatLit(*e->cast()); case Expression::E_SETLIT: return _t.mapSetLit(*e->cast()); case Expression::E_BOOLLIT: return _t.mapBoolLit(*e->cast()); case Expression::E_STRINGLIT: return _t.mapStringLit(*e->cast()); case Expression::E_ID: return _t.mapId(*e->cast()); case Expression::E_ANON: return _t.mapAnonVar(*e->cast()); case Expression::E_ARRAYLIT: return _t.mapArrayLit(*e->cast()); case Expression::E_ARRAYACCESS: return _t.mapArrayAccess(*e->cast()); case Expression::E_COMP: return _t.mapComprehension(*e->cast()); case Expression::E_ITE: return _t.mapITE(*e->cast()); case Expression::E_BINOP: return _t.mapBinOp(*e->cast()); case Expression::E_UNOP: return _t.mapUnOp(*e->cast()); case Expression::E_CALL: return _t.mapCall(*e->cast()); case Expression::E_VARDECL: return _t.mapVarDecl(*e->cast()); case Expression::E_LET: return _t.mapLet(*e->cast()); case Expression::E_TI: return _t.mapTypeInst(*e->cast()); case Expression::E_TIID: return _t.mapTIId(*e->cast()); default: assert(false); return typename T::ret(); break; } } }; class Document { private: int level; public: Document() : level(0) {} virtual ~Document() {} int getLevel() { return level; } // Make this object a child of "d". virtual void setParent(Document* d) { level = d->level + 1; } }; class BreakPoint: public Document { private: bool dontSimplify; public: BreakPoint() { dontSimplify = false; } BreakPoint(bool ds) { dontSimplify = ds; } virtual ~BreakPoint() {} void setDontSimplify(bool b) { dontSimplify = b; } bool getDontSimplify() { return dontSimplify; } }; class StringDocument: public Document { private: std::string stringDocument; public: StringDocument() {} virtual ~StringDocument() {} StringDocument(std::string s) : stringDocument(s) {} std::string getString() { return stringDocument; } void setString(std::string s) { stringDocument = s; } }; class DocumentList: public Document { private: std::vector docs; std::string beginToken; std::string separator; std::string endToken; bool unbreakable; bool alignment; public: virtual ~DocumentList() { std::vector::iterator it; for (it = docs.begin(); it != docs.end(); it++) { delete *it; } } DocumentList(std::string _beginToken = "", std::string _separator = "", std::string _endToken = "", bool _alignment = true); void addDocumentToList(Document* d) { docs.push_back(d); d->setParent(this); } void setParent(Document* d) { Document::setParent(d); std::vector::iterator it; for (it = docs.begin(); it != docs.end(); it++) { (*it)->setParent(this); } } void addStringToList(std::string s) { addDocumentToList(new StringDocument(s)); } void addBreakPoint(bool b = false) { addDocumentToList(new BreakPoint(b)); } std::vector getDocs() { return docs; } void setList(std::vector ld) { docs = ld; } std::string getBeginToken() { return beginToken; } std::string getEndToken() { return endToken; } std::string getSeparator() { return separator; } bool getUnbreakable() { return unbreakable; } void setUnbreakable(bool b) { unbreakable = b; } bool getAlignment() { return alignment; } }; DocumentList::DocumentList(std::string _beginToken, std::string _separator, std::string _endToken, bool _alignment) { beginToken = _beginToken; separator = _separator; endToken = _endToken; alignment = _alignment; unbreakable = false; } class Line { private: int indentation; int lineLength; std::vector text; public: Line() : indentation(0), lineLength(0), text(0) {} Line(const Line& l) : indentation(l.indentation), lineLength(l.lineLength), text(l.text) {} Line(const int indent) : indentation(indent), lineLength(0), text(0) {} bool operator==(const Line& l) { return &l == this; } void setIndentation(int i) { indentation = i; } int getLength() const { return lineLength; } int getIndentation() const { return indentation; } int getSpaceLeft(int maxwidth); void addString(const std::string& s); void concatenateLines(Line& l); void print(std::ostream& os) const { for (int i = 0; i < getIndentation(); i++) { os << " "; } std::vector::const_iterator it; for (it = text.begin(); it != text.end(); it++) { os << (*it); } os << "\n"; } }; int Line::getSpaceLeft(int maxwidth) { return maxwidth - lineLength - indentation; } void Line::addString(const std::string& s) { lineLength += static_cast(s.size()); text.push_back(s); } void Line::concatenateLines(Line& l) { text.insert(text.end(), l.text.begin(), l.text.end()); lineLength += l.lineLength; } class LinesToSimplify { private: std::map > lines; // (i,j) in parent <=> j can only be simplified if i is simplified std::vector > parent; /* * if i can't simplify, remove j and his parents */ //mostRecentlyAdded[level] = line of the most recently added std::map mostRecentlyAdded; public: std::vector* getLinesForPriority(int p) { std::map >::iterator it; for (it = lines.begin(); it != lines.end(); it++) { if (it->first == p) return &(it->second); } return NULL; } void addLine(int p, int l, int par = -1) { if (par == -1) { for (int i = p - 1; i >= 0; i--) { std::map::iterator it = mostRecentlyAdded.find(i); if (it != mostRecentlyAdded.end()) { par = it->second; break; } } } if (par != -1) parent.push_back(std::pair(l, par)); mostRecentlyAdded.insert(std::pair(p,l)); std::map >::iterator it; for (it = lines.begin(); it != lines.end(); it++) { if (it->first == p) { it->second.push_back(l); return; } } std::vector v; v.push_back(l); lines.insert(std::pair >(p, v)); } void decrementLine(std::vector* vec, int l) { std::vector::iterator vit; if (vec != NULL) { for (vit = vec->begin(); vit != vec->end(); vit++) { if (*vit >= l) *vit = *vit - 1; } } //Now the map std::map >::iterator it; for (it = lines.begin(); it != lines.end(); it++) { for (vit = it->second.begin(); vit != it->second.end(); vit++) { if (*vit >= l) *vit = *vit - 1; } } //And the parent table std::vector >::iterator vpit; for (vpit = parent.begin(); vpit != parent.end(); vpit++) { if (vpit->first >= l) vpit->first--; if (vpit->second >= l) vpit->second--; } } void remove(LinesToSimplify& lts){ std::map >::iterator it; for(it = lts.lines.begin(); it != lts.lines.end(); it++){ std::vector::iterator vit; for(vit = it->second.begin(); vit != it->second.end(); vit++){ remove(NULL, *vit, false); } } } void remove(std::vector* v, int i, bool success = true) { if (v != NULL) { v->erase(std::remove(v->begin(), v->end(), i), v->end()); } std::map >::iterator it; for (it = lines.begin(); it != lines.end(); it++) { std::vector* v = &(it->second); v->erase(std::remove(v->begin(), v->end(), i), v->end()); } //Call on its parent if (!success) { std::vector >::iterator vpit; for (vpit = parent.begin(); vpit != parent.end(); vpit++) { if (vpit->first == i && vpit->second != i && vpit->second != -1) { remove(v, vpit->second, false); } } } } std::vector* getLinesToSimplify() { std::vector* vec = new std::vector(); std::map >::iterator it; for (it = lines.begin(); it != lines.end(); it++) { std::vector& svec = it->second; vec->insert(vec->begin(), svec.begin(), svec.end()); } return vec; } }; Document* expressionToDocument(const Expression* e); Document* annotationToDocument(const Annotation& ann); Document* tiexpressionToDocument(const Type& type, const Expression* e) { DocumentList* dl = new DocumentList("","","",false); switch (type.ti()) { case Type::TI_PAR: break; case Type::TI_VAR: dl->addStringToList("var "); break; } if (type.ot()==Type::OT_OPTIONAL) dl->addStringToList("opt "); if (type.st()==Type::ST_SET) dl->addStringToList("set of "); if (e==NULL) { switch (type.bt()) { case Type::BT_INT: dl->addStringToList("int"); break; case Type::BT_BOOL: dl->addStringToList("bool"); break; case Type::BT_FLOAT: dl->addStringToList("float"); break; case Type::BT_STRING: dl->addStringToList("string"); break; case Type::BT_ANN: dl->addStringToList("ann"); break; case Type::BT_BOT: dl->addStringToList("bot"); break; case Type::BT_TOP: dl->addStringToList("top"); break; case Type::BT_UNKNOWN: dl->addStringToList("???"); break; } } else { dl->addDocumentToList(expressionToDocument(e)); } return dl; } class ExpressionDocumentMapper { public: typedef Document* ret; ret mapIntLit(const IntLit& il) { std::ostringstream oss; oss << il.v(); return new StringDocument(oss.str()); } ret mapFloatLit(const FloatLit& fl) { std::ostringstream oss; ppFloatVal(oss, fl.v()); return new StringDocument(oss.str()); } ret mapSetLit(const SetLit& sl) { DocumentList* dl; if (sl.isv()) { if (sl.isv()->size()==0) { dl = new DocumentList("1..0","",""); } else if (sl.isv()->size()==1) { dl = new DocumentList("", "..", ""); { std::ostringstream oss; oss << sl.isv()->min(0); dl->addDocumentToList(new StringDocument(oss.str())); } { std::ostringstream oss; oss << sl.isv()->max(0); dl->addDocumentToList(new StringDocument(oss.str())); } } else { dl = new DocumentList("{", ", ", "}", true); IntSetRanges isr(sl.isv()); for (Ranges::ToValues isv(isr); isv(); ++isv) { std::ostringstream oss; oss << isv.val(); dl->addDocumentToList(new StringDocument(oss.str())); } } } else if (sl.fsv()) { if (sl.fsv()->size()==0) { dl = new DocumentList("1.0..0.0","",""); } else if (sl.fsv()->size()==1) { dl = new DocumentList("", "..", ""); { std::ostringstream oss; ppFloatVal(oss, sl.fsv()->min(0)); dl->addDocumentToList(new StringDocument(oss.str())); } { std::ostringstream oss; ppFloatVal(oss, sl.fsv()->max(0)); dl->addDocumentToList(new StringDocument(oss.str())); } } else { dl = new DocumentList("", "++", "", true); FloatSetRanges fsr(sl.fsv()); for (; fsr(); ++fsr) { std::ostringstream oss; ppFloatVal(oss, fsr.min()); oss << ".."; ppFloatVal(oss, fsr.max()); dl->addDocumentToList(new StringDocument(oss.str())); } } } else { dl = new DocumentList("{", ", ", "}", true); for (unsigned int i = 0; i < sl.v().size(); i++) { dl->addDocumentToList(expressionToDocument((sl.v()[i]))); } } return dl; } ret mapBoolLit(const BoolLit& bl) { return new StringDocument(std::string(bl.v() ? "true" : "false")); } ret mapStringLit(const StringLit& sl) { std::ostringstream oss; oss << "\"" << Printer::escapeStringLit(sl.v()) << "\""; return new StringDocument(oss.str()); } ret mapId(const Id& id) { if (&id == constants().absent) return new StringDocument("<>"); if (id.idn()==-1) return new StringDocument(id.v().str()); else { std::ostringstream oss; oss << "X_INTRODUCED_" << id.idn() << "_"; return new StringDocument(oss.str()); } } ret mapTIId(const TIId& id) { return new StringDocument("$"+id.v().str()); } ret mapAnonVar(const AnonVar&) { return new StringDocument("_"); } ret mapArrayLit(const ArrayLit& al) { /// TODO: test multi-dimensional arrays handling DocumentList* dl; int n = al.dims(); if (n == 1 && al.min(0) == 1) { dl = new DocumentList("[", ", ", "]"); for (unsigned int i = 0; i < al.size(); i++) dl->addDocumentToList(expressionToDocument(al[i])); } else if (n == 2 && al.min(0) == 1 && al.min(1) == 1) { dl = new DocumentList("[| ", " | ", " |]"); for (int i = 0; i < al.max(0); i++) { DocumentList* row = new DocumentList("", ", ", ""); for (int j = 0; j < al.max(1); j++) { row-> addDocumentToList(expressionToDocument(al[i * al.max(1) + j])); } dl->addDocumentToList(row); if (i != al.max(0) - 1) dl->addBreakPoint(true); // dont simplify } } else { dl = new DocumentList("", "", ""); std::stringstream oss; oss << "array" << n << "d"; dl->addStringToList(oss.str()); DocumentList* args = new DocumentList("(", ", ", ")"); for (int i = 0; i < al.dims(); i++) { oss.str(""); oss << al.min(i) << ".." << al.max(i); args->addStringToList(oss.str()); } DocumentList* array = new DocumentList("[", ", ", "]"); for (unsigned int i = 0; i < al.size(); i++) array->addDocumentToList(expressionToDocument(al[i])); args->addDocumentToList(array); dl->addDocumentToList(args); } return dl; } ret mapArrayAccess(const ArrayAccess& aa) { DocumentList* dl = new DocumentList("", "", ""); dl->addDocumentToList(expressionToDocument(aa.v())); DocumentList* args = new DocumentList("[", ", ", "]"); for (unsigned int i = 0; i < aa.idx().size(); i++) { args->addDocumentToList(expressionToDocument(aa.idx()[i])); } dl->addDocumentToList(args); return dl; } ret mapComprehension(const Comprehension& c) { std::ostringstream oss; DocumentList* dl; if (c.set()) dl = new DocumentList("{ ", " | ", " }"); else dl = new DocumentList("[ ", " | ", " ]"); dl->addDocumentToList(expressionToDocument(c.e())); DocumentList* head = new DocumentList("", " ", ""); DocumentList* generators = new DocumentList("", ", ", ""); for (int i = 0; i < c.n_generators(); i++) { DocumentList* gen = new DocumentList("", "", ""); DocumentList* idents = new DocumentList("", ", ", ""); for (int j = 0; j < c.n_decls(i); j++) { idents->addStringToList(c.decl(i, j)->id()->v().str()); } gen->addDocumentToList(idents); if (c.in(i)==NULL) { gen->addStringToList(" = "); gen->addDocumentToList(expressionToDocument(c.where(i))); } else { gen->addStringToList(" in "); gen->addDocumentToList(expressionToDocument(c.in(i))); if (c.where(i) != NULL) { gen->addStringToList(" where "); gen->addDocumentToList(expressionToDocument(c.where(i))); } } generators->addDocumentToList(gen); } head->addDocumentToList(generators); dl->addDocumentToList(head); return dl; } ret mapITE(const ITE& ite) { DocumentList* dl = new DocumentList("", "", ""); for (int i = 0; i < ite.size(); i++) { std::string beg = (i == 0 ? "if " : " elseif "); dl->addStringToList(beg); dl->addDocumentToList(expressionToDocument(ite.e_if(i))); dl->addStringToList(" then "); DocumentList* ifdoc = new DocumentList("", "", "", false); ifdoc->addBreakPoint(); ifdoc->addDocumentToList(expressionToDocument(ite.e_then(i))); dl->addDocumentToList(ifdoc); dl->addStringToList(" "); } dl->addBreakPoint(); dl->addStringToList("else "); DocumentList* elsedoc = new DocumentList("", "", "", false); elsedoc->addBreakPoint(); elsedoc->addDocumentToList(expressionToDocument(ite.e_else())); dl->addDocumentToList(elsedoc); dl->addStringToList(" "); dl->addBreakPoint(); dl->addStringToList("endif"); return dl; } ret mapBinOp(const BinOp& bo) { Parentheses ps = needParens(&bo, bo.lhs(), bo.rhs()); DocumentList* opLeft; DocumentList* dl; DocumentList* opRight; bool linebreak = false; if (ps & PN_LEFT) opLeft = new DocumentList("(", " ", ")"); else opLeft = new DocumentList("", " ", ""); opLeft->addDocumentToList(expressionToDocument(bo.lhs())); std::string op; switch (bo.op()) { case BOT_PLUS: op = "+"; break; case BOT_MINUS: op = "-"; break; case BOT_MULT: op = "*"; break; case BOT_POW: op = "^"; break; case BOT_DIV: op = "/"; break; case BOT_IDIV: op = " div "; break; case BOT_MOD: op = " mod "; break; case BOT_LE: op = " < "; break; case BOT_LQ: op = "<="; break; case BOT_GR: op = " > "; break; case BOT_GQ: op = ">="; break; case BOT_EQ: op = "=="; break; case BOT_NQ: op = "!="; break; case BOT_IN: op = " in "; break; case BOT_SUBSET: op = " subset "; break; case BOT_SUPERSET: op = " superset "; break; case BOT_UNION: op = " union "; break; case BOT_DIFF: op = " diff "; break; case BOT_SYMDIFF: op = " symdiff "; break; case BOT_INTERSECT: op = " intersect "; break; case BOT_PLUSPLUS: op = "++"; linebreak = true; break; case BOT_EQUIV: op = " <-> "; break; case BOT_IMPL: op = " -> "; break; case BOT_RIMPL: op = " <- "; break; case BOT_OR: op = " \\/ "; linebreak = true; break; case BOT_AND: op = " /\\ "; linebreak = true; break; case BOT_XOR: op = " xor "; break; case BOT_DOTDOT: op = ".."; break; default: assert(false); break; } dl = new DocumentList("", op, ""); if (ps & PN_RIGHT) opRight = new DocumentList("(", " ", ")"); else opRight = new DocumentList("", "", ""); opRight->addDocumentToList(expressionToDocument(bo.rhs())); dl->addDocumentToList(opLeft); if (linebreak) dl->addBreakPoint(); dl->addDocumentToList(opRight); return dl; } ret mapUnOp(const UnOp& uo) { DocumentList* dl = new DocumentList("", "", ""); std::string op; switch (uo.op()) { case UOT_NOT: op = "not "; break; case UOT_PLUS: op = "+"; break; case UOT_MINUS: op = "-"; break; default: assert(false); break; } dl->addStringToList(op); DocumentList* unop; bool needParen = (uo.e()->isa() || uo.e()->isa()); if (needParen) unop = new DocumentList("(", " ", ")"); else unop = new DocumentList("", " ", ""); unop->addDocumentToList(expressionToDocument(uo.e())); dl->addDocumentToList(unop); return dl; } ret mapCall(const Call& c) { if (c.n_args() == 1) { /* * if we have only one argument, and this is an array comprehension, * we convert it into the following syntax * forall (f(i,j) | i in 1..10) * --> * forall (i in 1..10) (f(i,j)) */ const Expression* e = c.arg(0); if (e->isa()) { const Comprehension* com = e->cast(); if (!com->set()) { DocumentList* dl = new DocumentList("", " ", ""); dl->addStringToList(c.id().str()); DocumentList* args = new DocumentList("", " ", "", false); DocumentList* generators = new DocumentList("", ", ", ""); for (int i = 0; i < com->n_generators(); i++) { DocumentList* gen = new DocumentList("", "", ""); DocumentList* idents = new DocumentList("", ", ", ""); for (int j = 0; jn_decls(i); j++) { idents->addStringToList( com->decl(i,j)->id()->v().str()); } gen->addDocumentToList(idents); if (com->in(i) == NULL) { gen->addStringToList(" = "); gen->addDocumentToList(expressionToDocument(com->where(i))); } else { gen->addStringToList(" in "); gen->addDocumentToList(expressionToDocument(com->in(i))); if (com->where(i) != NULL) { gen->addStringToList(" where "); gen->addDocumentToList(expressionToDocument(com->where(i))); } } generators->addDocumentToList(gen); } args->addStringToList("("); args->addDocumentToList(generators); args->addStringToList(")"); args->addStringToList("("); args->addBreakPoint(); args->addDocumentToList(expressionToDocument(com->e())); dl->addDocumentToList(args); dl->addBreakPoint(); dl->addStringToList(")"); return dl; } } } std::string beg = c.id().str() + "("; DocumentList* dl = new DocumentList(beg, ", ", ")"); for (unsigned int i = 0; i < c.n_args(); i++) { dl->addDocumentToList(expressionToDocument(c.arg(i))); } return dl; } ret mapVarDecl(const VarDecl& vd) { std::ostringstream oss; DocumentList* dl = new DocumentList("", "", ""); dl->addDocumentToList(expressionToDocument(vd.ti())); dl->addStringToList(": "); if (vd.id()->idn()==-1) { dl->addStringToList(vd.id()->v().str()); } else { std::ostringstream oss; oss << "X_INTRODUCED_" << vd.id()->idn() << "_"; dl->addStringToList(oss.str()); } if (vd.introduced()) { dl->addStringToList(" ::var_is_introduced "); } if (!vd.ann().isEmpty()) { dl->addDocumentToList(annotationToDocument(vd.ann())); } if (vd.e()) { dl->addStringToList(" = "); dl->addDocumentToList(expressionToDocument(vd.e())); } return dl; } ret mapLet(const Let& l) { DocumentList* letin = new DocumentList("", "", "", false); DocumentList* lets = new DocumentList("", " ", "", true); DocumentList* inexpr = new DocumentList("", "", ""); bool ds = l.let().size() > 1; for (unsigned int i = 0; i < l.let().size(); i++) { if (i != 0) lets->addBreakPoint(ds); DocumentList* exp = new DocumentList("", " ", ","); const Expression* li = l.let()[i]; if (!li->isa()) exp->addStringToList("constraint"); exp->addDocumentToList(expressionToDocument(li)); lets->addDocumentToList(exp); } inexpr->addDocumentToList(expressionToDocument(l.in())); letin->addBreakPoint(ds); letin->addDocumentToList(lets); DocumentList* letin2 = new DocumentList("", "", "", false); letin2->addBreakPoint(); letin2->addDocumentToList(inexpr); DocumentList* dl = new DocumentList("", "", ""); dl->addStringToList("let {"); dl->addDocumentToList(letin); dl->addBreakPoint(ds); dl->addStringToList("} in ("); dl->addDocumentToList(letin2); //dl->addBreakPoint(); dl->addStringToList(")"); return dl; } ret mapTypeInst(const TypeInst& ti) { DocumentList* dl = new DocumentList("", "", ""); if (ti.isarray()) { dl->addStringToList("array ["); DocumentList* ran = new DocumentList("", ", ", ""); for (unsigned int i = 0; i < ti.ranges().size(); i++) { ran->addDocumentToList(tiexpressionToDocument(Type::parint(), ti.ranges()[i])); } dl->addDocumentToList(ran); dl->addStringToList("] of "); } dl->addDocumentToList(tiexpressionToDocument(ti.type(),ti.domain())); return dl; } }; Document* annotationToDocument(const Annotation& ann) { DocumentList* dl = new DocumentList(" :: ", " :: ", ""); for (ExpressionSetIter it = ann.begin(); it != ann.end(); ++it) { dl->addDocumentToList(expressionToDocument(*it)); } return dl; } Document* expressionToDocument(const Expression* e) { if (e==NULL) return new StringDocument("NULL"); ExpressionDocumentMapper esm; ExpressionMapper em(esm); DocumentList* dl = new DocumentList("", "", ""); Document* s = em.map(e); dl->addDocumentToList(s); if (!e->isa() && !e->ann().isEmpty()) { dl->addDocumentToList(annotationToDocument(e->ann())); } return dl; } class ItemDocumentMapper { public: typedef Document* ret; ret mapIncludeI(const IncludeI& ii) { std::ostringstream oss; oss << "include \"" << ii.f() << "\";"; return new StringDocument(oss.str()); } ret mapVarDeclI(const VarDeclI& vi) { DocumentList* dl = new DocumentList("", " ", ";"); dl->addDocumentToList(expressionToDocument(vi.e())); return dl; } ret mapAssignI(const AssignI& ai) { DocumentList* dl = new DocumentList("", " = ", ";"); dl->addStringToList(ai.id().str()); dl->addDocumentToList(expressionToDocument(ai.e())); return dl; } ret mapConstraintI(const ConstraintI& ci) { DocumentList* dl = new DocumentList("constraint ", " ", ";"); dl->addDocumentToList(expressionToDocument(ci.e())); return dl; } ret mapSolveI(const SolveI& si) { DocumentList* dl = new DocumentList("", "", ";"); dl->addStringToList("solve"); if (!si.ann().isEmpty()) dl->addDocumentToList(annotationToDocument(si.ann())); switch (si.st()) { case SolveI::ST_SAT: dl->addStringToList(" satisfy"); break; case SolveI::ST_MIN: dl->addStringToList(" minimize "); dl->addDocumentToList(expressionToDocument(si.e())); break; case SolveI::ST_MAX: dl->addStringToList(" maximize "); dl->addDocumentToList(expressionToDocument(si.e())); break; } return dl; } ret mapOutputI(const OutputI& oi) { DocumentList* dl = new DocumentList("output ", " ", ";"); dl->addDocumentToList(expressionToDocument(oi.e())); return dl; } ret mapFunctionI(const FunctionI& fi) { DocumentList* dl; if (fi.ti()->type().isann() && fi.e() == NULL) { dl = new DocumentList("annotation ", " ", ";", false); } else if (fi.ti()->type() == Type::parbool()) { dl = new DocumentList("test ", "", ";", false); } else if (fi.ti()->type() == Type::varbool()) { dl = new DocumentList("predicate ", "", ";", false); } else { dl = new DocumentList("function ", "", ";", false); dl->addDocumentToList(expressionToDocument(fi.ti())); dl->addStringToList(": "); } dl->addStringToList(fi.id().str()); if (fi.params().size() > 0) { DocumentList* params = new DocumentList("(", ", ", ")"); for (unsigned int i = 0; i < fi.params().size(); i++) { DocumentList* par = new DocumentList("", "", ""); par->setUnbreakable(true); par->addDocumentToList(expressionToDocument(fi.params()[i])); params->addDocumentToList(par); } dl->addDocumentToList(params); } if (!fi.ann().isEmpty()) { dl->addDocumentToList(annotationToDocument(fi.ann())); } if (fi.e()) { dl->addStringToList(" = "); dl->addBreakPoint(); dl->addDocumentToList(expressionToDocument(fi.e())); } return dl; } }; class PrettyPrinter { public: /* * \brief Constructor for class Pretty Printer * \param maxwidth (default 80) : number of rows * \param indentationBase : spaces that represent the atomic number of spaces * \param sim : whether we want to simplify the result * \param deepSimp : whether we want to simplify at each breakpoint or not */ PrettyPrinter(int _maxwidth = 80, int _indentationBase = 4, bool sim = false, bool deepSimp = false); void print(Document* d); void print(std::ostream& os) const; private: int maxwidth; int indentationBase; int currentLine; int currentItem; std::vector > items; std::vector linesToSimplify; std::vector linesNotToSimplify; bool simp; bool deeplySimp; void addItem(); void addLine(int indentation, bool bp = false, bool ds = false, int level = 0); static std::string printSpaces(int n); const std::vector& getCurrentItemLines() const; void printDocument(Document* d, bool alignment, int startColAlignment, const std::string& before = "", const std::string& after = ""); void printDocList(DocumentList* d, int startColAlignment, const std::string& before = "", const std::string& after = ""); void printStringDoc(StringDocument* d, bool alignment, int startColAlignment, const std::string& before = "", const std::string& after = ""); void printString(const std::string& s, bool alignment, int startColAlignment); bool simplify(int item, int line, std::vector* vec); void simplifyItem(int item); }; void PrettyPrinter::print(Document* d) { addItem(); addLine(0); printDocument(d, true, 0); if (simp) simplifyItem(currentItem); } PrettyPrinter::PrettyPrinter(int _maxwidth, int _indentationBase, bool sim, bool deepsim) { maxwidth = _maxwidth; indentationBase = _indentationBase; currentLine = -1; currentItem = -1; simp = sim; deeplySimp = deepsim; } const std::vector& PrettyPrinter::getCurrentItemLines() const { return items[currentItem]; } void PrettyPrinter::addLine(int indentation, bool bp, bool simpl, int level) { items[currentItem].push_back(Line(indentation)); currentLine++; if (bp && deeplySimp) { linesToSimplify[currentItem].addLine(level, currentLine); if (!simpl) linesNotToSimplify[currentItem].addLine(0, currentLine); } } void PrettyPrinter::addItem() { items.push_back(std::vector()); linesToSimplify.push_back(LinesToSimplify()); linesNotToSimplify.push_back(LinesToSimplify()); currentItem++; currentLine = -1; } void PrettyPrinter::print(std::ostream& os) const { std::vector::const_iterator it; int nItems = static_cast(items.size()); for (int item = 0; item < nItems; item++) { for (it = items[item].begin(); it != items[item].end(); it++) { it->print(os); } // os << std::endl; } } std::string PrettyPrinter::printSpaces(int n) { std::string result; for (int i = 0; i < n; i++) { result += " "; } return result; } void PrettyPrinter::printDocument(Document* d, bool alignment, int alignmentCol, const std::string& before, const std::string& after) { if (DocumentList* dl = dynamic_cast(d)) { printDocList(dl, alignmentCol, before, after); } else if (StringDocument* sd = dynamic_cast(d)) { printStringDoc(sd, alignment, alignmentCol, before, after); } else if (BreakPoint* bp = dynamic_cast(d)) { printString(before, alignment, alignmentCol); addLine(alignmentCol, deeplySimp, !bp->getDontSimplify(), d->getLevel()); printString(after, alignment, alignmentCol); } else { throw InternalError("PrettyPrinter::print : Wrong type of document"); } } void PrettyPrinter::printStringDoc(StringDocument* d, bool alignment, int alignmentCol, const std::string& before, const std::string& after) { std::string s; if (d != NULL) s = d->getString(); s = before + s + after; printString(s, alignment, alignmentCol); } void PrettyPrinter::printString(const std::string& s, bool alignment, int alignmentCol) { Line& l = items[currentItem][currentLine]; int size = static_cast(s.size()); if (size <= l.getSpaceLeft(maxwidth)) { l.addString(s); } else { int col = alignment && maxwidth - alignmentCol >= size ? alignmentCol : indentationBase; addLine(col); items[currentItem][currentLine].addString(s); } } void PrettyPrinter::printDocList(DocumentList* d, int alignmentCol, const std::string& super_before, const std::string& super_after) { std::vector ld = d->getDocs(); std::string beginToken = d->getBeginToken(); std::string separator = d->getSeparator(); std::string endToken = d->getEndToken(); bool _alignment = d->getAlignment(); if (d->getUnbreakable()) { addLine(alignmentCol); } int currentCol = items[currentItem][currentLine].getIndentation() + items[currentItem][currentLine].getLength(); int newAlignmentCol = _alignment ? currentCol + static_cast(beginToken.size()) : alignmentCol; int vectorSize = static_cast(ld.size()); int lastVisibleElementIndex; for (int i = 0; i < vectorSize; i++) { if (!dynamic_cast(ld[i])) lastVisibleElementIndex = i; } if (vectorSize == 0) { printStringDoc(NULL, true, newAlignmentCol, super_before + beginToken, endToken + super_after); } for (int i = 0; i < vectorSize; i++) { Document* subdoc = ld[i]; bool bp = false; if (dynamic_cast(subdoc)) { if (!_alignment) newAlignmentCol += indentationBase; bp = true; } std::string af, be; if (i != vectorSize - 1) { if (bp || lastVisibleElementIndex <= i) af = ""; else af = separator; } else { af = endToken + super_after; } if (i == 0) { be = super_before + beginToken; } else { be = ""; } printDocument(subdoc, _alignment, newAlignmentCol, be, af); } if (d->getUnbreakable()) { simplify(currentItem, currentLine, NULL); } } void PrettyPrinter::simplifyItem(int item) { linesToSimplify[item].remove(linesNotToSimplify[item]); std::vector* vec = (linesToSimplify[item].getLinesToSimplify()); while (!vec->empty()) { if (!simplify(item, (*vec)[0], vec)) break; } delete vec; } bool PrettyPrinter::simplify(int item, int line, std::vector* vec) { if (line == 0) { linesToSimplify[item].remove(vec, line, false); return false; } if (items[item][line].getLength() > items[item][line - 1].getSpaceLeft(maxwidth)) { linesToSimplify[item].remove(vec, line, false); return false; } else { linesToSimplify[item].remove(vec, line, true); items[item][line - 1].concatenateLines(items[item][line]); items[item].erase(items[item].begin() + line); linesToSimplify[item].decrementLine(vec, line); currentLine--; } return true; } Printer::Printer(std::ostream& os, int width, bool flatZinc, EnvI* env0) : env(env0), ism(NULL), printer(NULL), _os(os), _width(width), _flatZinc(flatZinc) {} void Printer::init(void) { if (ism==NULL) { ism = new ItemDocumentMapper(); printer = new PrettyPrinter(_width, 4, true, true); } } Printer::~Printer(void) { delete printer; delete ism; } void Printer::p(Document* d) { printer->print(d); printer->print(_os); delete printer; printer = new PrettyPrinter(_width,4,true,true); } void Printer::p(const Item* i) { Document* d; switch (i->iid()) { case Item::II_INC: d = ism->mapIncludeI(*i->cast()); break; case Item::II_VD: d = ism->mapVarDeclI(*i->cast()); break; case Item::II_ASN: d = ism->mapAssignI(*i->cast()); break; case Item::II_CON: d = ism->mapConstraintI(*i->cast()); break; case Item::II_SOL: d = ism->mapSolveI(*i->cast()); break; case Item::II_OUT: d = ism->mapOutputI(*i->cast()); break; case Item::II_FUN: d = ism->mapFunctionI(*i->cast()); break; } p(d); delete d; } void Printer::print(const Expression* e) { if (_width==0) { PlainPrinter p(_os,_flatZinc,env); p.p(e); } else { init(); Document* d = expressionToDocument(e); p(d); delete d; } } void Printer::print(const Item* i) { if (_width==0) { PlainPrinter p(_os,_flatZinc,env); p.p(i); } else { init(); p(i); } } void Printer::print(const Model* m) { if (_width==0) { PlainPrinter p(_os,_flatZinc,env); for (unsigned int i = 0; i < m->size(); i++) { p.p((*m)[i]); } } else { init(); for (unsigned int i = 0; i < m->size(); i++) { p((*m)[i]); } } } } void debugprint(MiniZinc::Expression* e) { std::cerr << *e << "\n"; } void debugprint(MiniZinc::Item* i) { std::cerr << *i; } void debugprint(MiniZinc::Model* m) { MiniZinc::Printer p(std::cerr,0); p.print(m); } void debugprint(const MiniZinc::Location& loc) { std::cerr << loc << std::endl; } libminizinc-2.4.2/lib/process.cpp000066400000000000000000000015011360574160400167610ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include namespace MiniZinc { #ifdef _WIN32 std::exception_ptr winExceptions[2]; void TimeOut(HANDLE hProcess, bool* doneStdout, bool* doneStderr, int timeout, std::timed_mutex* mtx) { if (timeout > 0) { if (!mtx->try_lock_for(std::chrono::milliseconds(timeout))) { if ( (!*doneStdout) || (!*doneStderr) ) { *doneStdout = true; *doneStderr = true; TerminateProcess(hProcess,0); } } } } #endif } libminizinc-2.4.2/lib/solns2out.cpp000066400000000000000000000430271360574160400172640ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was ! distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include using namespace std; using namespace MiniZinc; void Solns2Out::printHelp(ostream& os) { os << "Solution output options:" << std::endl << " --ozn-file \n Read output specification from ozn file." << std::endl << " -o , --output-to-file \n Filename for generated output." << std::endl << " -i , --ignore-lines , --ignore-leading-lines \n Ignore the first lines in the FlatZinc solution stream." << std::endl << " --soln-sep , --soln-separator , --solution-separator \n Specify the string printed after each solution (as a separate line).\n The default is to use the same as FlatZinc, \"----------\"." << std::endl << " --soln-comma , --solution-comma \n Specify the string used to separate solutions.\n The default is the empty string." << std::endl << " --unsat-msg (--unsatisfiable-msg), --unbounded-msg, --unsatorunbnd-msg,\n" " --unknown-msg, --error-msg, --search-complete-msg \n" " Specify solution status messages. The defaults:\n" " \"=====UNSATISFIABLE=====\", \"=====UNSATorUNBOUNDED=====\", \"=====UNBOUNDED=====\",\n" " \"=====UNKNOWN=====\", \"=====ERROR=====\", \"==========\", respectively." << std::endl << " --non-unique\n Allow duplicate solutions.\n" << " -c, --canonicalize\n Canonicalize the output solution stream (i.e., buffer and sort).\n" << " --output-non-canonical \n Non-buffered solution output file in case of canonicalization.\n" << " --output-raw \n File to dump the solver's raw output (not for hard-linked solvers)\n" // Unclear how to exit then: // << " --number-output \n Maximal number of different solutions printed." << std::endl << " --no-output-comments\n Do not print comments in the FlatZinc solution stream." << std::endl << " --output-time\n Print timing information in the FlatZinc solution stream." << std::endl << " --no-flush-output\n Don't flush output stream after every line." << std::endl ; } bool Solns2Out::processOption(int& i, std::vector& argv) { CLOParser cop( i, argv ); std::string oznfile; if ( cop.getOption( "--ozn-file", &oznfile) ) { initFromOzn(oznfile); } else if ( cop.getOption( "-o --output-to-file", &_opt.flag_output_file) ) { } else if ( cop.getOption( "--no-flush-output" ) ) { _opt.flag_output_flush = false; } else if ( cop.getOption( "--no-output-comments" ) ) { _opt.flag_output_comments = false; } else if ( cop.getOption( "-i --ignore-lines --ignore-leading-lines", &_opt.flag_ignore_lines ) ) { } else if ( cop.getOption( "--output-time" ) ) { _opt.flag_output_time = true; } else if ( cop.getOption( "--soln-sep --soln-separator --solution-separator", &_opt.solution_separator ) ) { } else if ( cop.getOption( "--soln-comma --solution-comma", &_opt.solution_comma ) ) { } else if ( cop.getOption( "--unsat-msg --unsatisfiable-msg", &_opt.unsatisfiable_msg ) ) { } else if ( cop.getOption( "--unbounded-msg", &_opt.unbounded_msg ) ) { } else if ( cop.getOption( "--unsatorunbnd-msg", &_opt.unsatorunbnd_msg ) ) { } else if ( cop.getOption( "--unknown-msg", &_opt.unknown_msg ) ) { } else if ( cop.getOption( "--error-msg", &_opt.error_msg ) ) { } else if ( cop.getOption( "--search-complete-msg", &_opt.search_complete_msg ) ) { } else if ( cop.getOption( "--unique") ) { _opt.flag_unique = true; } else if ( cop.getOption( "--non-unique") ) { _opt.flag_unique = false; } else if ( cop.getOption( "-c --canonicalize") ) { _opt.flag_canonicalize = true; } else if ( cop.getOption( "--output-non-canonical --output-non-canon", &_opt.flag_output_noncanonical) ) { } else if ( cop.getOption( "--output-raw", &_opt.flag_output_raw) ) { // } else if ( cop.getOption( "--number-output", &_opt.flag_number_output ) ) { } else if ( _opt.flag_standaloneSolns2Out ) { std::string oznfile(argv[i]); if (oznfile.length()<=4) { return false; } size_t last_dot = oznfile.find_last_of('.'); if (last_dot == string::npos) { return false; } std::string extension = oznfile.substr(last_dot,string::npos); if (extension == ".ozn") { initFromOzn(oznfile); return true; } return false; } else { return false; } return true; } bool Solns2Out::initFromEnv(Env* pE) { assert(pE); pEnv=pE; init(); return true; } void Solns2Out::initFromOzn(const std::string& filename) { std::vector filenames( 1, filename ); includePaths.push_back(stdlibDir+"/std/"); for (unsigned int i=0; i(), "", "", includePaths, false, false, false, errstream))) { std::vector typeErrors; pEnv->model(pOutput); MZN_ASSERT_HARD_MSG( pEnv, "solns2out: could not allocate Env" ); pEnv_guard.reset( pEnv ); MiniZinc::typecheck(*pEnv,pOutput,typeErrors,false,false); MiniZinc::registerBuiltins(*pEnv); pEnv->envi().swap_output(); init(); } else { throw Error(errstream.str()); } } } Solns2Out::DE& Solns2Out::findOutputVar( ASTString id ) { declNewOutput(); auto it = declmap.find( id.str() ); MZN_ASSERT_HARD_MSG( declmap.end()!=it, "solns2out_base: unexpected id in output: " << id ); return it->second; } void Solns2Out::restoreDefaults() { for (unsigned int i=0; isize(); i++) { if (VarDeclI* vdi = (*getModel())[i]->dyn_cast()) { if (vdi->e()->id()->idn()!=-1 || vdi->e()->id()->v()!="_mzn_solution_checker") { GCLock lock; auto& de = findOutputVar(vdi->e()->id()->str()); vdi->e()->e(de.second()); vdi->e()->evaluated(false); } } } fNewSol2Print = false; } void Solns2Out::parseAssignments(string& solution) { std::vector se; unique_ptr sm( parseFromString(*pEnv, solution, "solution received from solver", includePaths, true, false, false, log, se) ); if (sm.get()==NULL) throw Error("solns2out_base: could not parse solution"); solution = ""; for (unsigned int i=0; isize(); i++) { if (AssignI* ai = (*sm)[i]->dyn_cast()) { auto& de = findOutputVar(ai->id()); ai->e()->type(de.first->type()); ai->decl(de.first); typecheck(*pEnv, getModel(), ai); if (Call* c = ai->e()->dyn_cast()) { // This is an arrayXd call, make sure we get the right builtin assert(c->arg(c->n_args()-1)->isa()); for (unsigned int i=0; in_args(); i++) c->arg(i)->type(Type::parsetint()); c->arg(c->n_args()-1)->type(de.first->type()); c->decl(getModel()->matchFn(pEnv->envi(), c, false)); } de.first->e(ai->e()); } } declNewOutput(); } void Solns2Out::declNewOutput() { fNewSol2Print=true; status = SolverInstance::SAT; } bool Solns2Out::evalOutput( const string& s_ExtraInfo ) { if ( !fNewSol2Print ) return true; ostringstream oss; if (!__evalOutput( oss )) return false; if ( !checkerModel.empty() ) checkSolution(oss); bool fNew=true; if ( _opt.flag_unique || _opt.flag_canonicalize ) { auto res = sSolsCanon.insert( oss.str() ); if ( !res.second ) // repeated solution fNew = false; } if ( fNew ) { ++nSolns; if ( _opt.flag_canonicalize ) { if ( pOfs_non_canon.get() ) if ( pOfs_non_canon->good() ) { (*pOfs_non_canon) << oss.str(); (*pOfs_non_canon) << comments; if ( s_ExtraInfo.size() ) { (*pOfs_non_canon) << s_ExtraInfo; if ( '\n'!=s_ExtraInfo.back() ) /// TODO is this enough to check EOL? (*pOfs_non_canon) << '\n'; } if (_opt.flag_output_time) (*pOfs_non_canon) << "% time elapsed: " << starttime.stoptime() << "\n"; if (!_opt.solution_separator.empty()) (*pOfs_non_canon) << _opt.solution_separator << '\n'; if ( _opt.flag_output_flush ) pOfs_non_canon->flush(); } } else { if ( _opt.solution_comma.size() && nSolns>1 ) getOutput() << _opt.solution_comma << '\n'; getOutput() << oss.str(); } } getOutput() << comments; // print them now ???? comments = ""; if ( s_ExtraInfo.size() ) { getOutput() << s_ExtraInfo; if ( '\n'!=s_ExtraInfo.back() ) /// TODO is this enough to check EOL? getOutput() << '\n'; } if ( fNew && _opt.flag_output_time) getOutput() << "% time elapsed: " << starttime.stoptime() << "\n"; if ( fNew && !_opt.flag_canonicalize && !_opt.solution_separator.empty()) getOutput() << _opt.solution_separator << '\n'; if ( _opt.flag_output_flush ) getOutput().flush(); restoreDefaults(); // cleans data. evalOutput() should not be called again w/o assigning new data. return true; } void Solns2Out::checkSolution(std::ostream& os) { #ifdef HAS_GECODE std::ostringstream checker; checker << checkerModel; { GCLock lock; for (unsigned int i=0; isize(); i++) { if (VarDeclI* vdi = (*getModel())[i]->dyn_cast()) { if (vdi->e()->ann().contains(constants().ann.mzn_check_var)) { if (Call* cev = vdi->e()->ann().getCall(constants().ann.mzn_check_enum_var)) { checker << vdi->e()->id()->str() << "= to_enum(" << *cev->arg(0)->cast() << "," << *eval_par(getEnv()->envi(),vdi->e()->e()) << ");"; } else { checker << vdi->e()->id()->str() << "=" << *eval_par(getEnv()->envi(),vdi->e()->e()) << ";"; } } } } } std::ostringstream oss_err; MznSolver slv(oss_err,oss_err); slv.s2out._opt.solution_separator = ""; try { std::vector args({"--solver","org.minizinc.gecode_presolver"}); slv.run(args, checker.str(), "minizinc", "checker.mzc"); } catch (const LocationException& e) { oss_err << e.loc() << ":" << std::endl; oss_err << e.what() << ": " << e.msg() << std::endl; } catch (const Exception& e) { std::string what = e.what(); oss_err << what << (what.empty() ? "" : ": ") <envi().evalOutput( fout ); } return true; } bool Solns2Out::evalStatus( SolverInstance::Status status ) { if ( _opt.flag_canonicalize ) __evalOutputFinal( _opt.flag_output_flush ); __evalStatusMsg( status ); fStatusPrinted = 1; return true; } bool Solns2Out::__evalOutputFinal( bool ) { /// Print the canonical list for ( auto& sol : sSolsCanon ) { if ( _opt.solution_comma.size() && &sol != &*sSolsCanon.begin() ) getOutput() << _opt.solution_comma << '\n'; getOutput() << sol; if (!_opt.solution_separator.empty()) getOutput() << _opt.solution_separator << '\n'; } return true; } bool Solns2Out::__evalStatusMsg( SolverInstance::Status status ) { std::map stat2msg; stat2msg[ SolverInstance::OPT ] = _opt.search_complete_msg; stat2msg[ SolverInstance::UNSAT ] = _opt.unsatisfiable_msg; stat2msg[ SolverInstance::UNBND ] = _opt.unbounded_msg; stat2msg[ SolverInstance::UNSATorUNBND ] = _opt.unsatorunbnd_msg; stat2msg[ SolverInstance::UNKNOWN ] = _opt.unknown_msg; stat2msg[ SolverInstance::ERROR ] = _opt.error_msg; stat2msg[ SolverInstance::NONE ] = ""; auto it=stat2msg.find(status); if ( stat2msg.end()!=it ) { getOutput() << comments; if (!it->second.empty()) getOutput() << it->second << '\n'; if ( _opt.flag_output_time) getOutput() << "% time elapsed: " << starttime.stoptime() << "\n"; if ( _opt.flag_output_flush ) getOutput().flush(); Solns2Out::status = status; } else { getOutput() << comments; if ( _opt.flag_output_flush ) getOutput().flush(); MZN_ASSERT_HARD_MSG( SolverInstance::SAT==status, // which is ignored "solns2out_base: undefined solution status code " << status ); Solns2Out::status = SolverInstance::SAT; } comments = ""; return true; } void Solns2Out::init() { declmap.clear(); for (unsigned int i=0; isize(); i++) { if (OutputI* oi = (*getModel())[i]->dyn_cast()) { outputExpr = oi->e(); } else if (VarDeclI* vdi = (*getModel())[i]->dyn_cast()) { if (vdi->e()->id()->idn()==-1 && vdi->e()->id()->v()=="_mzn_solution_checker") { checkerModel = eval_string(getEnv()->envi(), vdi->e()->e()); if (checkerModel.size() > 0 && checkerModel[0]=='@') { checkerModel = FileUtils::decodeBase64(checkerModel); FileUtils::inflateString(checkerModel); } } else { GCLock lock; declmap.insert(pair(vdi->e()->id()->str().str(),DE(vdi->e(),vdi->e()->e()))); } } } /// Main output file if ( 0==pOut ) { if ( _opt.flag_output_file.size() ) { pOut.reset( new ofstream( _opt.flag_output_file ) ); MZN_ASSERT_HARD_MSG( pOut.get(), "solns2out_base: could not allocate stream object for file output into " << _opt.flag_output_file ); checkIOStatus( pOut->good(), _opt.flag_output_file); } } /// Non-canonical output if ( _opt.flag_canonicalize && _opt.flag_output_noncanonical.size() ) { pOfs_non_canon.reset( new ofstream( _opt.flag_output_noncanonical ) ); MZN_ASSERT_HARD_MSG( pOfs_non_canon.get(), "solns2out_base: could not allocate stream object for non-canon output" ); checkIOStatus( pOfs_non_canon->good(), _opt.flag_output_noncanonical, 0); } /// Raw output if ( _opt.flag_output_raw.size() ) { pOfs_raw.reset( new ofstream( _opt.flag_output_raw ) ); MZN_ASSERT_HARD_MSG( pOfs_raw.get(), "solns2out_base: could not allocate stream object for raw output" ); checkIOStatus( pOfs_raw->good(), _opt.flag_output_raw, 0); } /// Assume all options are set before nLinesIgnore = _opt.flag_ignore_lines; } Solns2Out::Solns2Out(std::ostream& os0, std::ostream& log0, const std::string& stdlibDir0) : os(os0), log(log0), stdlibDir(stdlibDir0) {} Solns2Out::~Solns2Out() { getOutput() << comments; if ( _opt.flag_output_flush ) getOutput() << flush; } ostream& Solns2Out::getOutput() { return (( pOut.get() && pOut->good() ) ? *pOut : os); } ostream& Solns2Out::getLog() { return log; } bool Solns2Out::feedRawDataChunk(const char* data) { istringstream solstream( data ); while (solstream.good()) { string line; getline(solstream, line); if (line_part.size()) { line = line_part + line; line_part.clear(); } if (solstream.eof()) { // wait next chunk line_part = line; break; // to get to raw output } if (line.size()) if ('\r' == line.back()) line.pop_back(); // For WIN files if ( nLinesIgnore > 0 ) { --nLinesIgnore; continue; } if ( mapInputStatus.empty() ) createInputMap(); auto it = mapInputStatus.find( line ); if ( mapInputStatus.end()!=it ) { if ( SolverInstance::SAT==it->second ) { parseAssignments( solution ); evalOutput(); } else { evalStatus( it->second ); } } else { solution += line + '\n'; if ( _opt.flag_output_comments ) { std::istringstream iss( line ); char c='_'; iss >> skipws >> c; if ( iss.good() && '%'==c) { // Feed comments directly getOutput() << line << '\n'; if ( _opt.flag_output_flush ) getOutput().flush(); if ( pOfs_non_canon.get() ) if ( pOfs_non_canon->good() ) ( *pOfs_non_canon ) << line << '\n'; } } } } if ( pOfs_raw.get() ) { (*pOfs_raw.get()) << data; if (_opt.flag_output_flush) pOfs_raw->flush(); } return true; } void Solns2Out::createInputMap() { mapInputStatus[ _opt.search_complete_msg_00 ] = SolverInstance::OPT; mapInputStatus[ _opt.solution_separator_00 ] = SolverInstance::SAT; mapInputStatus[ _opt.unsatisfiable_msg_00 ] = SolverInstance::UNSAT; mapInputStatus[ _opt.unbounded_msg_00 ] = SolverInstance::UNBND; mapInputStatus[ _opt.unsatorunbnd_msg_00 ] = SolverInstance::UNSATorUNBND; mapInputStatus[ _opt.unknown_msg_00 ] = SolverInstance::UNKNOWN; mapInputStatus[ _opt.error_msg ] = SolverInstance::ERROR; } void Solns2Out::printStatistics(ostream& os) { os << "%%%mzn-stat: nSolutions=" << nSolns << "\n"; } libminizinc-2.4.2/lib/solver.cpp000066400000000000000000000613121360574160400166230ustar00rootroot00000000000000 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* This (main) file coordinates flattening and solving. * The corresponding modules are flexibly plugged in * as derived classes, prospectively from DLLs. * A flattening module should provide MinZinc::GetFlattener() * A solving module should provide an object of a class derived from SolverFactory. * Need to get more flexible for multi-pass & multi-solving stuff TODO */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #include #include #include #include using namespace std; #include using namespace MiniZinc; #ifdef HAS_GUROBI #include #endif #ifdef HAS_CPLEX #include #endif #ifdef HAS_OSICBC #include #endif #ifdef HAS_XPRESS #include #endif #ifdef HAS_GECODE #include #endif #ifdef HAS_GEAS #include #endif #ifdef HAS_SCIP #include #endif #include #include #include #include #include #include SolverInitialiser::SolverInitialiser(void) { #ifdef HAS_GUROBI Gurobi_SolverFactoryInitialiser _gurobi_init; #endif #ifdef HAS_CPLEX static Cplex_SolverFactoryInitialiser _cplex_init; #endif #ifdef HAS_OSICBC static OSICBC_SolverFactoryInitialiser _osicbc_init; #endif #ifdef HAS_XPRESS static Xpress_SolverFactoryInitialiser _xpress_init; #endif #ifdef HAS_GECODE static Gecode_SolverFactoryInitialiser _gecode_init; #endif #ifdef HAS_GEAS static Geas_SolverFactoryInitialiser _geas_init; #endif #ifdef HAS_SCIP static SCIP_SolverFactoryInitialiser _scip_init; #endif static FZN_SolverFactoryInitialiser _fzn_init; static MZN_SolverFactoryInitialiser _mzn_init; static NL_SolverFactoryInitialiser _nl_init; } MZNFZNSolverFlag MZNFZNSolverFlag::std(const std::string& n0) { const std::string argFlags("-I -n -p -r"); if (argFlags.find(n0) != std::string::npos) return MZNFZNSolverFlag(FT_ARG,n0); return MZNFZNSolverFlag(FT_NOARG,n0); } MZNFZNSolverFlag MZNFZNSolverFlag::extra(const std::string& n0, const std::string& t0) { return MZNFZNSolverFlag(t0=="bool" ? FT_NOARG : FT_ARG, n0); } // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SolverRegistry* MiniZinc::getGlobalSolverRegistry() { static SolverRegistry sr; return &sr; } void SolverRegistry::addSolverFactory(SolverFactory* pSF) { assert(pSF); sfstorage.push_back(pSF); } void SolverRegistry::removeSolverFactory(SolverFactory* pSF) { auto it = find(sfstorage.begin(), sfstorage.end(), pSF); assert(pSF); sfstorage.erase(it); } /// Function createSI also adds each SI to the local storage SolverInstanceBase * SolverFactory::createSI(Env& env, std::ostream& log, SolverInstanceBase::Options* opt) { SolverInstanceBase *pSI = doCreateSI(env,log,opt); if (!pSI) { throw InternalError("SolverFactory: failed to initialize solver "+getDescription()); } sistorage.resize(sistorage.size()+1); sistorage.back().reset(pSI); return pSI; } /// also providing a destroy function for a DLL or just special allocator etc. void SolverFactory::destroySI(SolverInstanceBase * pSI) { auto it = sistorage.begin(); for ( ; it != sistorage.end(); ++ it) if (it->get() == pSI) break; if (sistorage.end() == it) { cerr << " SolverFactory: failed to remove solver at " << pSI << endl; throw InternalError(" SolverFactory: failed to remove solver"); } sistorage.erase(it); } MznSolver::MznSolver(std::ostream& os0, std::ostream& log0) : solver_configs(log0), flt(os0,log0,solver_configs.mznlibDir()), executable_name(""), os(os0), log(log0), s2out(os0,log0,solver_configs.mznlibDir()) {} MznSolver::~MznSolver() { // if (si) // first the solver // CleanupSolverInterface(si); // TODO cleanup the used solver interfaces si=0; si_opt=nullptr; GC::trigger(); } bool MznSolver::ifMzn2Fzn() { return is_mzn2fzn; } bool MznSolver::ifSolns2out() { return s2out._opt.flag_standaloneSolns2Out; } void MznSolver::addSolverInterface(SolverFactory* sf) { si = sf->createSI(*flt.getEnv(), log, si_opt); assert(si); if (s2out.getEnv()==NULL) s2out.initFromEnv( flt.getEnv() ); si->setSolns2Out( &s2out ); if (flag_compiler_verbose) log // << " ---------------------------------------------------------------------------\n" << " % SOLVING PHASE\n" << sf->getDescription(si_opt) << endl; } void MznSolver::addSolverInterface() { GCLock lock; if (sf==NULL) { if ( getGlobalSolverRegistry()->getSolverFactories().empty() ) { log << " MznSolver: NO SOLVER FACTORIES LINKED." << endl; assert( 0 ); } sf = getGlobalSolverRegistry()->getSolverFactories().back(); } addSolverInterface(sf); } void MznSolver::printUsage() { os << executable_name << ": "; if ( ifMzn2Fzn() ) { os << "MiniZinc to FlatZinc converter.\n" << "Usage: " << executable_name << " [] [-I ] .mzn [.dzn ...]" << std::endl; } else if (ifSolns2out()) { os << "Solutions to output translator.\n" << "Usage: " << executable_name << " [] .ozn" << std::endl; } else { os << "MiniZinc driver.\n" << "Usage: " << executable_name << " [] [-I ] .mzn [.dzn ...] or just .fzn" << std::endl; } } void MznSolver::printHelp(const std::string& selectedSolver) { printUsage(); os << "General options:" << std::endl << " --help, -h\n Print this help message." << std::endl << " --version\n Print version information." << std::endl << " --solvers\n Print list of available solvers." << std::endl << " --time-limit \n Stop after milliseconds (includes compilation and solving)." << std::endl << " --solver , --solver .msc\n Select solver to use." << std::endl << " --help \n Print help for a particular solver." << std::endl << " -v, -l, --verbose\n Print progress/log statements. Note that some solvers may log to stdout." << std::endl << " --verbose-compilation\n Print progress/log statements for compilation." << std::endl << " -s, --statistics\n Print statistics." << std::endl << " --compiler-statistics\n Print statistics for compilation." << std::endl << " -c, --compile\n Compile only (do not run solver)." << std::endl << " --config-dirs\n Output configuration directories." << std::endl; if (selectedSolver.empty()) { flt.printHelp(os); os << endl; if ( !ifMzn2Fzn() ) { s2out.printHelp(os); os << endl; } os << "Available solvers (get help using --help ):" << endl; std::vector solvers = solver_configs.solvers(); if (solvers.size()==0) cout << " none.\n"; for (unsigned int i=0; igetSolverFactories().rbegin(); it != getGlobalSolverRegistry()->getSolverFactories().rend(); ++it) { if ((*it)->getId()==solverId) { os << endl; (*it)->printHelp(os); if (!sc.executable().empty() && !sc.extraFlags().empty()) { os << "Extra solver flags (use with "; os << (sc.supportsMzn() ? "--mzn-flags" : "--fzn-flags") << ")" << endl; for (const SolverConfig::ExtraFlag& ef: sc.extraFlags()) { os << " " << ef.flag << endl << " " << ef.description << endl; } } found = true; } } if (!found) { os << "No help found for solver " << selectedSolver << endl; } } } void addFlags(const std::string& sep, const std::vector& in_args, std::vector& out_args) { for(const std::string& arg : in_args) { out_args.push_back(sep); out_args.push_back(arg); } } MznSolver::OptionStatus MznSolver::processOptions(std::vector& argv) { executable_name = argv[0]; executable_name = executable_name.substr(executable_name.find_last_of("/\\") + 1); size_t lastdot = executable_name.find_last_of('.'); if (lastdot != std::string::npos) { executable_name = executable_name.substr(0, lastdot); } string solver; bool mzn2fzn_exe = (executable_name=="mzn2fzn"); if (mzn2fzn_exe) { is_mzn2fzn=true; } else if (executable_name=="solns2out") { s2out._opt.flag_standaloneSolns2Out=true; flag_is_solns2out=true; } bool compileSolutionChecker = false; int i=1, j=1; int argc = static_cast(argv.size()); if (argc < 2) return OPTION_ERROR; for (i=1; i i+1) { printHelp(argv[i+1]); } else { printHelp(); } return OPTION_FINISH; } if (argv[i]=="--version") { flt.printVersion(cout); return OPTION_FINISH; } if (argv[i]=="--solvers") { cout << "MiniZinc driver.\nAvailable solver configurations:\n"; std::vector solvers = solver_configs.solvers(); if (solvers.size()==0) cout << " none.\n"; for (unsigned int i=0; i0 && solver != argv[i]) { log << "Only one --solver option allowed" << endl; return OPTION_ERROR; } solver = argv[i]; } else if (argv[i]=="-c" || argv[i]=="--compile") { is_mzn2fzn = true; } else if (argv[i]=="-v" || argv[i]=="--verbose" || argv[i]=="-l") { flag_verbose = true; flag_compiler_verbose = true; } else if (argv[i]=="--verbose-compilation") { flag_compiler_verbose = true; } else if (argv[i]=="-s" || argv[i]=="--statistics") { flag_statistics = true; flag_compiler_statistics = true; } else if (argv[i]=="--compiler-statistics") { flag_compiler_statistics = true; } else { if ((argv[i]=="--fzn-cmd" || argv[i]=="--flatzinc-cmd") && solver.empty()) { solver = "org.minizinc.mzn-fzn"; } if (argv[i]=="--compile-solution-checker") { compileSolutionChecker = true; } if (argv[i]=="--ozn-file") { flag_is_solns2out = true; } argv[j++] = argv[i]; } } argv.resize(j); argc = j; if ( (mzn2fzn_exe || compileSolutionChecker) && solver.empty()) { solver = "org.minizinc.mzn-fzn"; } if (flag_verbose) { argv.push_back("--verbose-solving"); argc++; } if (flag_statistics) { argv.push_back("--solver-statistics"); argc++; } flt.set_flag_output_by_default(ifMzn2Fzn()); bool isMznMzn = false; if (!flag_is_solns2out) { try { const SolverConfig& sc = solver_configs.config(solver); string solverId; if (sc.executable().empty()) { solverId = sc.id(); } else if (sc.supportsMzn()) { solverId = "org.minizinc.mzn-mzn"; } else if (sc.supportsFzn()) { solverId = "org.minizinc.mzn-fzn"; } else if (sc.supportsNL()) { solverId = "org.minizinc.mzn-nl"; } else { log << "Selected solver does not support MiniZinc, FlatZinc or NL input." << endl; return OPTION_ERROR; } for (auto it = getGlobalSolverRegistry()->getSolverFactories().begin(); it != getGlobalSolverRegistry()->getSolverFactories().end(); ++it) { if ((*it)->getId()==solverId) { /// TODO: also check version (currently assumes all ids are unique) sf = *it; if (si_opt) { delete si_opt; } si_opt = sf->createOptions(); if (!sc.executable().empty() || solverId=="org.minizinc.mzn-fzn" || solverId=="org.minizinc.mzn-nl") { std::vector acceptedFlags; for (auto& sf : sc.stdFlags()) acceptedFlags.push_back(MZNFZNSolverFlag::std(sf)); for (auto& ef : sc.extraFlags()) acceptedFlags.push_back(MZNFZNSolverFlag::extra(ef.flag,ef.flag_type)); // Collect arguments required for underlying exe vector fzn_mzn_flags; if (sc.needsStdlibDir()) { fzn_mzn_flags.push_back("--stdlib-dir"); fzn_mzn_flags.push_back(FileUtils::share_directory()); } if (sc.needsMznExecutable()) { fzn_mzn_flags.push_back("--minizinc-exe"); fzn_mzn_flags.push_back(FileUtils::progpath() + "/" + executable_name); } if (sc.supportsMzn()) { isMznMzn = true; static_cast(sf)->setAcceptedFlags(si_opt, acceptedFlags); std::vector additionalArgs_s; additionalArgs_s.push_back("-m"); if (sc.executable_resolved().size()) { additionalArgs_s.push_back(sc.executable_resolved()); } else { additionalArgs_s.push_back(sc.executable()); } if(!fzn_mzn_flags.empty()) { addFlags("--mzn-flag", fzn_mzn_flags, additionalArgs_s); } // This should maybe be moved to fill in fzn_mzn_flags when // --find-muses is implemented (these arguments will be passed // through to the subsolver of findMUS) if (!sc.mznlib().empty()) { if (sc.mznlib().substr(0,2)=="-G") { additionalArgs_s.push_back("--mzn-flag"); additionalArgs_s.push_back(sc.mznlib()); } else { additionalArgs_s.push_back("--mzn-flag"); additionalArgs_s.push_back("-I"); additionalArgs_s.push_back("--mzn-flag"); std::string _mznlib; if (sc.mznlib_resolved().size()) { _mznlib = sc.mznlib_resolved(); } else { _mznlib = sc.mznlib(); } additionalArgs_s.push_back(_mznlib); } } for (i=0; iprocessOption(si_opt, i, additionalArgs_s); if (!success) { log << "Solver backend " << solverId << " does not recognise option " << additionalArgs_s[i] << "." << endl; return OPTION_ERROR; } } } else { // supports fzn or nl std::vector additionalArgs; if (sc.supportsFzn()) { static_cast(sf)->setAcceptedFlags(si_opt, acceptedFlags); additionalArgs.push_back("--fzn-cmd"); } else { // supports nl additionalArgs.push_back("--nl-cmd"); } if (sc.executable_resolved().size()) { additionalArgs.push_back(sc.executable_resolved()); } else { additionalArgs.push_back(sc.executable()); } if(!fzn_mzn_flags.empty()) { if (sc.supportsFzn()) { addFlags("--fzn-flag", fzn_mzn_flags, additionalArgs); } else { addFlags("--nl-flag", fzn_mzn_flags, additionalArgs); } } if (sc.needsPathsFile()) { // Instruct flattener to hold onto paths int i=0; vector args {"--keep-paths"}; flt.processOption(i, args); // Instruct FznSolverInstance to write a path file // and pass it to the executable with --paths arg additionalArgs.push_back("--fzn-needs-paths"); } if (!sc.needsSolns2Out()) { additionalArgs.push_back("--fzn-output-passthrough"); } int i=0; for (i=0; iprocessOption(si_opt, i, additionalArgs); if (!success) { log << "Solver backend " << solverId << " does not recognise option " << additionalArgs[i] << "." << endl; return OPTION_ERROR; } } } } if (!sc.mznlib().empty()) { if (sc.mznlib().substr(0,2)=="-G") { std::vector additionalArgs({sc.mznlib()}); int i=0; if (!flt.processOption(i, additionalArgs)) { log << "Flattener does not recognise option " << sc.mznlib() << endl; return OPTION_ERROR; } } else { std::vector additionalArgs(2); additionalArgs[0] = "-I"; if (sc.mznlib_resolved().size()) { additionalArgs[1] = sc.mznlib_resolved(); } else { additionalArgs[1] = sc.mznlib(); } int i=0; if (!flt.processOption(i, additionalArgs)) { log << "Flattener does not recognise option -I." << endl; return OPTION_ERROR; } } } if (!sc.defaultFlags().empty()) { std::vector addedArgs; addedArgs.push_back(argv[0]); // excutable name for (auto& df : sc.defaultFlags()) { addedArgs.push_back(df); } for (int i=1; iprocessOption(si_opt, i, argv)) { } else { std::string executable_name(argv[0]); executable_name = executable_name.substr(executable_name.find_last_of("/\\") + 1); log << executable_name << ": Unrecognized option or bad format `" << argv[i] << "'" << endl; return OPTION_ERROR; } } return OPTION_OK; } else { for (i=1; iprocessFlatZinc(); } SolverInstance::Status status = getSI()->solve(); GCLock lock; if (status==SolverInstance::SAT || status==SolverInstance::OPT) { if ( !getSI()->getSolns2Out()->fStatusPrinted ) getSI()->getSolns2Out()->evalStatus( status ); } else { if ( !getSI()->getSolns2Out()->fStatusPrinted ) getSI()->getSolns2Out()->evalStatus( status ); } if (si_opt->printStatistics) getSI()->printStatistics(); if (flag_statistics) getSI()->getSolns2Out()->printStatistics(log); return status; } SolverInstance::Status MznSolver::run(const std::vector& args0, const std::string& model, const std::string& exeName, const std::string& modelName) { using namespace std::chrono; steady_clock::time_point startTime = steady_clock::now(); std::vector args = {exeName}; for (auto a : args0) args.push_back(a); switch (processOptions(args)) { case OPTION_FINISH: return SolverInstance::NONE; case OPTION_ERROR: printUsage(); os << "More info with \"" << exeName << " --help\"\n"; return SolverInstance::ERROR; case OPTION_OK: break; } if (flag_is_solns2out && (ifMzn2Fzn() || sf==NULL || sf->getId() != "org.minizinc.mzn-mzn") && !flt.hasInputFiles() && model.empty()) { // We are in solns2out mode while ( std::cin.good() ) { string line; getline( std::cin, line ); line += '\n'; // need eols as in t=raw stream s2out.feedRawDataChunk( line.c_str() ); } return SolverInstance::NONE; } if (!ifMzn2Fzn() && sf->getId() == "org.minizinc.mzn-mzn") { Env env; si = sf->createSI(env, log, si_opt); si->setSolns2Out( &s2out ); { // To be able to clean up flatzinc after PrcessFlt() GCLock lock; getSI()->_options->verbose = get_flag_verbose(); getSI()->_options->printStatistics = get_flag_statistics(); } getSI()->solve(); return SolverInstance::NONE; } try { flatten(model,modelName); } catch (Timeout&) { s2out.evalStatus( SolverInstance::UNKNOWN ); return SolverInstance::UNKNOWN; } if (!ifMzn2Fzn() && flag_overall_time_limit != 0) { steady_clock::time_point afterFlattening = steady_clock::now(); milliseconds passed = duration_cast(afterFlattening-startTime); milliseconds time_limit(flag_overall_time_limit); if (passed > time_limit) { s2out.evalStatus( getFltStatus() ); return SolverInstance::UNKNOWN; } int time_left = (time_limit-passed).count(); std::vector timeoutArgs(2); timeoutArgs[0] = "--solver-time-limit"; std::ostringstream oss; oss << time_left; timeoutArgs[1] = oss.str(); int i=0; sf->processOption(si_opt, i, timeoutArgs); } if (SolverInstance::UNKNOWN == getFltStatus()) { if ( !ifMzn2Fzn() ) { // only then // GCLock lock; // better locally, to enable cleanup after ProcessFlt() addSolverInterface(); return solve(); } return SolverInstance::NONE; } else { if ( !ifMzn2Fzn() ) s2out.evalStatus( getFltStatus() ); return getFltStatus(); } // Add evalOutput() here? TODO } libminizinc-2.4.2/lib/solver_config.cpp000066400000000000000000000674721360574160400201650ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include #include #include #include #include #include using namespace std; namespace MiniZinc { namespace { std::string getString(AssignI* ai) { if (StringLit* sl = ai->e()->dyn_cast()) { return sl->v().str(); } throw ConfigException("invalid configuration item (right hand side must be string)"); } bool getBool(AssignI* ai) { if (BoolLit* bl = ai->e()->dyn_cast()) { return bl->v(); } throw ConfigException("invalid configuration item (right hand side must be bool)"); } int getInt(AssignI* ai) { if (IntLit* il = ai->e()->dyn_cast()) { return static_cast(il->v().toInt()); } throw ConfigException("invalid configuration item (right hand side must be int)"); } std::vector getStringList(AssignI* ai) { if (ArrayLit* al = ai->e()->dyn_cast()) { std::vector ret; for (unsigned int i=0; isize(); i++) { if (StringLit* sl = (*al)[i]->dyn_cast()) { ret.push_back(sl->v().str()); } else { throw ConfigException("invalid configuration item (right hand side must be a list of strings)"); } } return ret; } throw ConfigException("invalid configuration item (right hand side must be a list of strings)"); } std::vector > getStringPairList(AssignI* ai) { if (ArrayLit* al = ai->e()->dyn_cast()) { std::vector > ret; if (al->dims()!=2 || al->min(1)!=1 || al->max(1)!=2) { throw ConfigException("invalid configuration item (right hand side must be a 2d array of strings)"); } for (unsigned int i=0; isize(); i+=2) { StringLit* sl1 = (*al)[i]->dyn_cast(); StringLit* sl2 = (*al)[i+1]->dyn_cast(); if (sl1 && sl2) { ret.push_back(std::make_pair(sl1->v().str(),sl2->v().str())); } else { throw ConfigException("invalid configuration item (right hand side must be a 2d array of strings)"); } } return ret; } throw ConfigException("invalid configuration item (right hand side must be a 2d array of strings)"); } std::vector > getDefaultOptionList(AssignI* ai) { if (ArrayLit* al = ai->e()->dyn_cast()) { std::vector > ret; if (al->size()==0) return ret; if (al->dims()!=2) { throw ConfigException("invalid configuration item (right hand side must be a 2d array of strings)"); } int nCols = al->max(1)-al->min(1)+1; if (nCols != 3) { throw ConfigException("invalid configuration item (right hand side must be a 2d array of strings with 3 columns)"); } for (unsigned int i=0; isize(); i+=nCols) { StringLit* sl0 = (*al)[i]->dyn_cast(); StringLit* sl1 = (*al)[i+1]->dyn_cast(); StringLit* sl2 = (*al)[i+2]->dyn_cast(); if (sl0 && sl1 && sl2) { ret.push_back(std::vector({sl0->v().str(),sl1->v().str(),sl2->v().str()})); } else { throw ConfigException("invalid configuration item (right hand side must be a list of strings)"); } } return ret; } throw ConfigException("invalid configuration item (right hand side must be a 2d array of strings)"); } std::vector getExtraFlagList(AssignI* ai) { if (ArrayLit* al = ai->e()->dyn_cast()) { std::vector ret; if (al->size()==0) return ret; if (al->dims()!=2) { throw ConfigException("invalid configuration item (right hand side must be a 2d array of strings)"); } int nCols = al->max(1)-al->min(1)+1; if (nCols < 2 || nCols > 4) { throw ConfigException("invalid configuration item (right hand side must be a 2d array of strings)"); } bool haveType = (nCols >= 3); bool haveDefault = (nCols >= 4); for (unsigned int i=0; isize(); i+=nCols) { StringLit* sl1 = (*al)[i]->dyn_cast(); StringLit* sl2 = (*al)[i+1]->dyn_cast(); StringLit* sl3 = haveType ? (*al)[i+2]->dyn_cast() : NULL; StringLit* sl4 = haveDefault ? (*al)[i+3]->dyn_cast() : NULL; std::string opt_type = sl3 ? sl3->v().str() : "bool"; std::string opt_def; if (sl4) { opt_def = sl4->v().str(); } else if (opt_type=="bool") { opt_def = "false"; } else if (opt_type=="int") { opt_def = "0"; } else if (opt_type=="float") { opt_def = "0.0"; } if (sl1 && sl2) { ret.emplace_back(sl1->v().str(),sl2->v().str(),opt_type,opt_def); } else { throw ConfigException("invalid configuration item (right hand side must be a 2d array of strings)"); } } return ret; } throw ConfigException("invalid configuration item (right hand side must be a 2d array of strings)"); } std::string getEnv(const char* v) { std::string ret; #ifdef _MSC_VER size_t len; getenv_s(&len, NULL, 0, v); if (len > 0) { char* p = static_cast(malloc(len*sizeof(char))); getenv_s(&len, p, len, v); if (len > 0) { ret = p; } free(p); } #else char* p = getenv(v); if (p) { ret = p; } #endif return ret; } char charToLower(char c) { return std::tolower(static_cast(c)); } std::string stringToLower(std::string s) { std::transform(s.begin(), s.end(), s.begin(), charToLower); return s; } struct SortByLowercase { bool operator ()(const std::string& n1, const std::string& n2) { for (size_t i=0; i& solvers; SortByLowercase sortByLowercase; SortByName(const std::vector& solvers0) : solvers(solvers0) {} bool operator ()(int idx1, int idx2) { return sortByLowercase(solvers[idx1].name(), solvers[idx2].name()); } }; } SolverConfig SolverConfig::load(string filename) { SolverConfig sc; sc._configFile = FileUtils::file_path(filename); ostringstream errstream; try { Env confenv; Model* m = NULL; if (JSONParser::fileIsJSON(filename)) { JSONParser jp(confenv.envi()); try { m = new Model; GCLock lock; jp.parse(m, filename); } catch (JSONError& e) { delete m; m=NULL; throw ConfigException(e.msg()); } } else { vector filenames; filenames.push_back(filename); m = parse(confenv,filenames, vector(), "", "", vector(), true, false, false, errstream); } if (m) { bool hadId = false; bool hadVersion = false; bool hadName = false; string basePath = FileUtils::dir_name(sc._configFile); for (unsigned int i=0; isize(); i++) { if (AssignI* ai = (*m)[i]->dyn_cast()) { if (ai->id()=="id") { sc._id = getString(ai); hadId = true; } else if (ai->id()=="name") { sc._name = getString(ai); hadName = true; } else if (ai->id()=="executable") { std::string exePath = getString(ai); sc._executable = exePath; std::string exe = FileUtils::find_executable(FileUtils::file_path(exePath, basePath)); int nr_found = (int) (! exe.empty()); std::string tmp = FileUtils::file_path(FileUtils::find_executable(exePath)); nr_found += (int) ( (! tmp.empty()) && tmp != exe); exe = exe.empty() ? tmp : exe; if (nr_found > 0) { sc._executable_resolved = exe; if (nr_found > 1) { std::cerr << "Warning: multiple executables '" << exePath << "' found on the system, using '" << exe << "'" << std::endl; } } } else if (ai->id()=="mznlib") { std::string libPath = getString(ai); sc._mznlib = libPath; if (!libPath.empty()) { if (libPath[0]=='-') { sc._mznlib_resolved = libPath; } else if (libPath.size() > 2 && libPath[0]=='.' && (libPath[1]=='/' || (libPath[1]=='.' && libPath[2]=='/'))) { sc._mznlib_resolved = FileUtils::file_path(libPath, basePath); } else { sc._mznlib_resolved = FileUtils::file_path(libPath, basePath); } } } else if (ai->id()=="version") { sc._version = getString(ai); hadVersion = true; } else if (ai->id()=="mznlibVersion") { sc._mznlibVersion = getInt(ai); } else if (ai->id()=="description") { sc._description = getString(ai); } else if (ai->id()=="contact") { sc._contact = getString(ai); } else if (ai->id()=="website") { sc._website = getString(ai); } else if (ai->id()=="supportsMzn") { sc._supportsMzn = getBool(ai); } else if (ai->id()=="supportsFzn") { sc._supportsFzn = getBool(ai); } else if (ai->id()=="supportsNL") { sc._supportsNL = getBool(ai); } else if (ai->id()=="needsSolns2Out") { sc._needsSolns2Out = getBool(ai); } else if (ai->id()=="isGUIApplication") { sc._isGUIApplication = getBool(ai); } else if (ai->id()=="needsMznExecutable") { sc._needsMznExecutable = getBool(ai); } else if (ai->id()=="needsStdlibDir") { sc._needsStdlibDir = getBool(ai); } else if (ai->id()=="needsPathsFile") { sc._needsPathsFile = getBool(ai); } else if (ai->id()=="tags") { sc._tags = getStringList(ai); } else if (ai->id()=="stdFlags") { sc._stdFlags = getStringList(ai); } else if (ai->id()=="requiredFlags") { sc._requiredFlags = getStringList(ai); } else if (ai->id()=="extraFlags") { sc._extraFlags = getExtraFlagList(ai); } else { throw ConfigException("invalid configuration item ("+ai->id().str()+")"); } } else { throw ConfigException("invalid configuration item"); } } if (!hadId) { throw ConfigException("invalid solver configuration (missing id)"); } if (!hadVersion) { throw ConfigException("invalid solver configuration (missing version)"); } if (!hadName) { throw ConfigException("invalid solver configuration (missing name)"); } } else { throw ConfigException(errstream.str()); } } catch (ConfigException&) { throw; } catch (Exception& e) { throw ConfigException(e.what()); } return sc; } class BuiltinSolverConfigs { public: std::unordered_map builtinSolvers; }; BuiltinSolverConfigs& builtinSolverConfigs(void) { static BuiltinSolverConfigs c; return c; } void SolverConfigs::addConfig(const MiniZinc::SolverConfig& sc) { int newIdx = static_cast(_solvers.size()); _solvers.push_back(sc); std::vector sc_tags = sc.tags(); std::string id = sc.id(); id = stringToLower(id); sc_tags.push_back(id); std::string name = sc.name(); name = stringToLower(name); sc_tags.push_back(name); for (auto t : sc_tags) { TagMap::iterator it = _tags.find(t); if (it==_tags.end()) { _tags.insert(std::make_pair(t,std::vector({newIdx}))); } else { it->second.push_back(newIdx); } } } std::vector SolverConfigs::solverConfigsPath(void) const { return _solver_path; } SolverConfigs::SolverConfigs(std::ostream& log) { #ifdef _MSC_VER const char* PATHSEP = ";"; #else const char* PATHSEP = ":"; #endif for (auto sc : builtinSolverConfigs().builtinSolvers) { addConfig(sc.second); } std::string mzn_solver_path = getEnv("MZN_SOLVER_PATH"); while (!mzn_solver_path.empty()) { size_t next_sep = mzn_solver_path.find(PATHSEP); string cur_path = mzn_solver_path.substr(0,next_sep); _solver_path.push_back(cur_path); if (next_sep != string::npos) mzn_solver_path = mzn_solver_path.substr(next_sep+1,string::npos); else mzn_solver_path = ""; } std::string userConfigDir = FileUtils::user_config_dir(); if (FileUtils::directory_exists(userConfigDir+"/solvers")) { _solver_path.push_back(userConfigDir+"/solvers"); } std::vector configFiles({FileUtils::global_config_file(),FileUtils::user_config_file()}); for (auto& cf : configFiles) { if (!cf.empty() && FileUtils::file_exists(cf)) { ostringstream errstream; try { Env userconfenv; Model* m = NULL; if (JSONParser::fileIsJSON(cf)) { JSONParser jp(userconfenv.envi()); try { m = new Model; GCLock lock; jp.parse(m, cf); } catch (JSONError&) { delete m; m=NULL; } } if (m) { for (unsigned int i=0; isize(); i++) { if (AssignI* ai = (*m)[i]->dyn_cast()) { if (ai->id()=="mzn_solver_path") { std::vector sp = getStringList(ai); for (auto s : sp) { _solver_path.push_back(s); } } else if (ai->id()=="mzn_lib_dir") { _mznlibDir = getString(ai); } else if (ai->id()=="tagDefaults") { std::vector > tagDefs = getStringPairList(ai); for (auto& td: tagDefs) { std::string tag = td.first; std::string solver_id = td.second; _tagDefault[tag] = solver_id; } } else if (ai->id()=="solverDefaults") { std::vector > solverDefs = getDefaultOptionList(ai); for (auto& sd: solverDefs) { assert(sd.size()==3); std::string solver = sd[0]; SolverDefaultMap::iterator it = _solverDefaultOptions.find(solver); if (it==_solverDefaultOptions.end()) { std::vector solverOptions({sd[1],sd[2]}); _solverDefaultOptions.insert(std::make_pair(solver, solverOptions)); } else { std::vector& opts = it->second; bool found=false; for (unsigned int i=0; i configFiles = FileUtils::directory_list(cur_path, "msc"); for (unsigned int i=0; i defaultOptions; for (auto& df : it->second) { if (!df.empty()) { defaultOptions.push_back(df); } } sc.defaultFlags(defaultOptions); } } } vector SolverConfigs::solvers() const { // Find default solver, if present std::string def_id; DefaultMap::const_iterator def_it = _tagDefault.find(""); if (def_it != _tagDefault.end()) { def_id = def_it->second; } // Create sorted list of solvers vector s; for (auto& sc: _solvers) { if (std::find(sc.tags().begin(), sc.tags().end(), "__internal__") != sc.tags().end()) continue; std::ostringstream oss; oss << sc.name() << " " << sc.version() << " (" << sc.id(); if (!def_id.empty() && sc.id()==def_id) { oss << ", default solver"; } for (std::string t: sc.tags()) { oss << ", " << t; } oss << ")"; s.push_back(oss.str()); } SortByLowercase sortByLowercase; std::sort(s.begin(),s.end(), sortByLowercase); return s; } std::string SolverConfigs::solverConfigsJSON() const { GCLock lock; std::ostringstream oss; // Find default solver, if present std::string def_id; DefaultMap::const_iterator def_it = _tagDefault.find(""); if (def_it != _tagDefault.end()) { def_id = def_it->second; } SortByName sortByName(_solvers); std::vector solversIdx(_solvers.size()); for (unsigned int i=0; i 4 && _s.substr(_s.size()-4)==".msc") { SolverConfig sc = SolverConfig::load(_s); addConfig(sc); s = sc.id()+"@"+sc.version(); } else { s = _s; } std::remove(s.begin(),s.end(),' '); s = stringToLower(s); std::vector tags; std::istringstream iss(s); std::string next_s; while (std::getline(iss,next_s,',')) { tags.push_back(next_s); } std::set defaultSolvers; std::set selectedSolvers; std::string firstTag; if (tags.empty()) { DefaultMap::const_iterator def_it = _tagDefault.find(""); if (def_it != _tagDefault.end()) { firstTag = def_it->second; } else { throw ConfigException("no solver selected"); } } else { firstTag = tags[0]; } TagMap::const_iterator tag_it = _tags.find(getTag(firstTag)); if (tag_it == _tags.end()) { throw ConfigException("no solver with tag "+getTag(firstTag)+" found"); } std::string tv = getVersion(firstTag); for (int sidx: tag_it->second) { if (tv.empty() || tv==_solvers[sidx].version()) selectedSolvers.insert(sidx); } DefaultMap::const_iterator def_it = _tagDefault.find(getTag(firstTag)); if (def_it != _tagDefault.end()) { defaultSolvers.insert(def_it->second); } for (unsigned int i=1; i newSolvers; for (int sidx: tag_it->second) { if (tv.empty() || tv==_solvers[sidx].version()) newSolvers.insert(sidx); } std::set intersection; std::set_intersection(selectedSolvers.begin(),selectedSolvers.end(), newSolvers.begin(),newSolvers.end(), std::inserter(intersection, intersection.begin())); selectedSolvers = intersection; if (selectedSolvers.empty()) { throw ConfigException("no solver with tags "+s+" found"); } def_it = _tagDefault.find(getTag(tags[i])); if (def_it != _tagDefault.end()) { defaultSolvers.insert(def_it->second); } } int selectedSolver=-1; if (selectedSolvers.size()>1) { // use default information for the tags to select a solver for (int sc_idx : selectedSolvers) { if (defaultSolvers.find(_solvers[sc_idx].id()) != defaultSolvers.end()) { selectedSolver = sc_idx; break; } } if (selectedSolver==-1) { selectedSolver = *selectedSolvers.begin(); } } else { selectedSolver = *selectedSolvers.begin(); } return _solvers[selectedSolver]; } void SolverConfigs::registerBuiltinSolver(const SolverConfig& sc) { builtinSolverConfigs().builtinSolvers.insert(make_pair(sc.id(),sc)); } } libminizinc-2.4.2/lib/solver_instance.cpp000066400000000000000000000006271360574160400205110ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include namespace MiniZinc { } libminizinc-2.4.2/lib/solver_instance_base.cpp000066400000000000000000000151601360574160400215010ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #undef ERROR // MICROsoft. #undef min #undef max #endif namespace MiniZinc { SolverInstanceBase::Status SolverInstanceBase::solve(void) { return SolverInstance__ERROR; } void SolverInstanceBase::reset(void) { assert(false); } void SolverInstanceBase::resetWithConstraints(Model::iterator begin, Model::iterator end) { assert(false); } void SolverInstanceBase::processPermanentConstraints(Model::iterator begin, Model::iterator end) { assert(false); } void Registry::add(const std::string& name, poster p) { _registry.insert(std::make_pair(name, p)); } void Registry::post(Call* c) { std::unordered_map::iterator it = _registry.find(c->id().str()); if (it == _registry.end()) { GCLock lock; throw InternalError("Error: solver backend cannot handle constraint: " + c->id().str() + "\n"); } it->second(_base, c); } void SolverInstanceBase::printSolution() { std::ostringstream oss; if ( _options->printStatistics ) printStatistics(1); // Insert stats before sol separator if ( 0==pS2Out ) { getEnv()->evalOutput(std::cout); // deprecated std::cout << oss.str(); if ( oss.str().size() && '\n'!=oss.str().back() ) std::cout << '\n'; std::cout << "----------" << std::endl; } else getSolns2Out()->evalOutput( oss.str() ); } void SolverInstanceBase2::printSolution() { GCLock lock; assignSolutionToOutput(); SolverInstanceBase::printSolution(); } // void // SolverInstanceBase::assignSolutionToOutput(void) { // for (VarDeclIterator it = getEnv()->output()->begin_vardecls(); it != getEnv()->output()->end_vardecls(); ++it) { // if (it->e()->e() == NULL) { // it->e()->e(getSolutionValue(it->e()->id())); // } // } // } void SolverInstanceBase2::assignSolutionToOutput() { GCLock lock; MZN_ASSERT_HARD_MSG( 0!=pS2Out, "Setup a Solns2Out object to use default solution extraction/reporting procs" ); if ( _varsWithOutput.empty() ) { for (VarDeclIterator it = getEnv()->flat()->begin_vardecls(); it != getEnv()->flat()->end_vardecls(); ++it) { if(!it->removed()) { VarDecl* vd = it->e(); if(!vd->ann().isEmpty()) { if(vd->ann().containsCall(constants().ann.output_array.aststr()) || vd->ann().contains(constants().ann.output_var) ) { _varsWithOutput.push_back(vd); } } } } } pS2Out->declNewOutput(); // Even for empty output decl //iterate over set of ids that have an output annotation && obtain their right hand side from the flat model for(unsigned int i=0; i<_varsWithOutput.size(); i++) { VarDecl* vd = _varsWithOutput[i]; //std::cout << "DEBUG: Looking at var-decl with output-annotation: " << *vd << std::endl; if(Call* output_array_ann = Expression::dyn_cast(getAnnotation(vd->ann(), constants().ann.output_array.aststr()))) { assert(vd->e()); if(ArrayLit* al = vd->e()->dyn_cast()) { std::vector array_elems; ArrayLit& array = *al; for(unsigned int j=0; jdyn_cast()) { //std::cout << "DEBUG: getting solution value from " << *id << " : " << id->v() << std::endl; array_elems.push_back(getSolutionValue(id)); } else if(FloatLit* floatLit = array[j]->dyn_cast()) { array_elems.push_back(floatLit); } else if(IntLit* intLit = array[j]->dyn_cast()) { array_elems.push_back(intLit); } else if(BoolLit* boolLit = array[j]->dyn_cast()) { array_elems.push_back(boolLit); } else if(SetLit* setLit = array[j]->dyn_cast()) { array_elems.push_back(setLit); } else if(StringLit* strLit = array[j]->dyn_cast()) { array_elems.push_back(strLit); } else { std::ostringstream oss; oss << "Error: array element " << *array[j] << " is not an id nor a literal"; throw InternalError(oss.str()); } } GCLock lock; ArrayLit* dims; Expression* e = output_array_ann->arg(0); if(ArrayLit* al = e->dyn_cast()) { dims = al; } else if(Id* id = e->dyn_cast()) { dims = id->decl()->e()->cast(); } else { throw -1; } std::vector > dims_v; for( int i=0;ilength();i++) { IntSetVal* isv = eval_intset(getEnv()->envi(), (*dims)[i]); if (isv->size()==0) { dims_v.push_back(std::pair(1,0)); } else { dims_v.push_back(std::pair(static_cast(isv->min().toInt()),static_cast(isv->max().toInt()))); } } ArrayLit* array_solution = new ArrayLit(Location(),array_elems,dims_v); KeepAlive ka(array_solution); auto& de = getSolns2Out()->findOutputVar(vd->id()->str().str()); de.first->e(array_solution); } } else if(vd->ann().contains(constants().ann.output_var)) { Expression* sol = getSolutionValue(vd->id()); vd->e(sol); auto& de = getSolns2Out()->findOutputVar(vd->id()->str().str()); de.first->e(sol); } } } void SolverInstanceBase::flattenSearchAnnotations(const Annotation& ann, std::vector& out) { for(ExpressionSetIter i = ann.begin(); i != ann.end(); ++i) { Expression* e = *i; if(e->isa() && (e->cast()->id().str() == "seq_search" || e->cast()->id().str() == "warm_start_array")) { Call* c = e->cast(); auto* anns = c->arg(0)->cast(); for(unsigned int i=0; isize(); i++) { Annotation subann; subann.add((*anns)[i]); flattenSearchAnnotations(subann, out); } } else { out.push_back(*i); } } } } // namespace MiniZinc libminizinc-2.4.2/lib/statistics.cpp000066400000000000000000000027031360574160400175020ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include namespace MiniZinc { /// TODO all key words should be standard and defined in 1 place void Statistics::print(std::ostream& os) { os << "%%%mzn-stat: solveTime=" << _time << std::endl << "%%%mzn-stat: nodes=" << _nodes << std::endl << "%%%mzn-stat: failures=" << _failures << std::endl << "%%%mzn-stat: objective=" << _objective << std::endl; }; void Statistics::time(unsigned long long t) { _time = t; } void Statistics::nodes(unsigned long long n) { _nodes = n; } void Statistics::failures(unsigned long long f) { _failures = f; } void Statistics::objective(double o) { _objective = o; } unsigned long long Statistics::time() { return _time; }; unsigned long long Statistics::nodes() { return _nodes; }; unsigned long long Statistics::failures() { return _failures; }; double Statistics::objective() { return _objective; }; Statistics& Statistics::operator+=(Statistics& s) { _time += s.time(); _nodes += s.nodes(); _failures += s.failures(); _objective = s.objective(); return *this; } } libminizinc-2.4.2/lib/support/000077500000000000000000000000001360574160400163165ustar00rootroot00000000000000libminizinc-2.4.2/lib/support/regex/000077500000000000000000000000001360574160400174305ustar00rootroot00000000000000libminizinc-2.4.2/lib/support/regex/lexer.lxx000066400000000000000000000024761360574160400213150ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Jip J. Dekker */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ %option noyywrap %option prefix="regex_yy" %{ #include #define YY_DECL int yylex() #include %} %% [ \t\n] { /* ignore white space */ } [0-9]+ { regex_yylval.iValue = std::atoi(regex_yytext); return R_INTEGER; } "|" { return R_UNION; } "+" { return R_PLUS; } "*" { return R_STAR; } "(" { return R_GROUP_OPEN; } ")" { return R_GROUP_CLOSE; } "?" { return R_OPTIONAL; } "{" { return R_QUANT_OPEN; } "}" { return R_QUANT_CLOSE; } "," { return R_COMMA; } "." { return R_ANY; } "[" { return R_CLASS_OPEN; } "]" { return R_CLASS_CLOSE; } "-" { return R_CLASS_RANGE; } "^" { return R_CLASS_NEG; } [A-Za-z][A-Za-z0-9_]* { regex_yylval.sValue = strdup(yytext); return R_IDENTIFIER; } "'"[^\\'\xa\xd\x0]*"'" { regex_yylval.sValue = strdup(yytext); return R_IDENTIFIER; } . { /* Catch all */ throw std::runtime_error("Illegal token in regular expression: '" + std::string(regex_yytext) + "'"); } %% libminizinc-2.4.2/lib/support/regex/parser.yxx000066400000000000000000000105211360574160400214750ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Jip J. Dekker */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ %{ #include #include #include #include #include #include #include using namespace Gecode; using namespace MiniZinc; typedef struct yy_buffer_state *YY_BUFFER_STATE; YY_BUFFER_STATE regex_yy_scan_string ( const char* yy_str ); extern int yylex(); extern FILE* yyin; typedef struct REContext{ REG* expr; const IntSetVal& dom; const std::unordered_map& idMap; } REContext; void yyerror(REContext& ctx, const char* s); %} %union { int iValue; char* sValue; std::set* setValue; Gecode::REG* rValue; } %parse-param {REContext& ctx} %token R_INTEGER %token R_GROUP_OPEN "(" %token R_GROUP_CLOSE ")" %token R_STAR "*" %token R_PLUS "+" %token R_ANY "." %token R_UNION "|" %token R_OPTIONAL "?" %token R_QUANT_OPEN "{" %token R_QUANT_CLOSE "}" %token R_COMMA "," %token R_CLASS_OPEN "[" %token R_CLASS_CLOSE "]" %token R_CLASS_RANGE "-" %token R_CLASS_NEG "^" %token R_IDENTIFIER %type literal %type regex expression term factor atom %type set_item set_items %start regex %% regex: expression { *ctx.expr = (*$1); delete $1; } expression: term | term "|" expression { *$1 = *$1 | *$3; delete $3; $$ = $1; } term: factor | factor term { *$1 = *$1 + *$2; delete $2; $$ = $1; } factor: atom | atom "*" { *$1 = *(*$1); $$ = $1; } | atom "+" { *$1 = +(*$1); $$ = $1; } | atom "?" { *$1 = (*$1)(0, 1); $$ = $1; } | atom "{" R_INTEGER "}" { *$1 = (*$1)($3, $3); $$ = $1; } | atom "{" R_INTEGER "," "}" { *$1 = (*$1)($3); $$ = $1; } | atom "{" R_INTEGER "," R_INTEGER "}" { *$1 = (*$1)($3, $5); $$ = $1; } atom: literal { $$ = new REG($1); } | "." { IntArgs range = IntArgs::create(ctx.dom.max().toInt() - ctx.dom.min().toInt() + 1, ctx.dom.min().toInt()); $$ = new REG(range); } | "[" set_items "]" { std::vector v; v.reserve($2->size()); for(auto i : *$2) { v.push_back(i); } delete $2; $$ = new REG(IntArgs(v)); } | "[" "^" set_items "]" { std::vector diff; std::set domain; for(int i = ctx.dom.min().toInt(); i<=ctx.dom.max().toInt(); ++i) { domain.insert(i); } std::set_difference( domain.begin(), domain.end(), $3->begin(), $3->end(), std::inserter(diff, diff.begin()) ); delete $3; $$ = new REG(IntArgs(diff)); } | "(" expression ")" { $$ = $2; } set_items: set_item | set_item set_items { $$ = $1; for (auto i : *$2) { $1->insert(i); } delete $2; } set_item: literal { $$ = new std::set({$1}); } | literal "-" literal { int from = $1; int to = $3; if (to < from) { std::swap(from,to); } $$ = new std::set; for(int i = from; i<=to; ++i) { $$->insert(i); } } literal: R_INTEGER | R_IDENTIFIER { std::string s($1); auto find = ctx.idMap.find(s); if (find == ctx.idMap.end()) { throw std::runtime_error("Unknown identifier: " + s); } $$ = find->second; } %% void yyerror(REContext& ctx, const char* s) { // TODO: Add error location throw std::runtime_error("Cannot parse regular expression: " + std::string(s)); } std::unique_ptr regex_from_string(const std::string& regex_str, const IntSetVal& domain, const std::unordered_map& identifiers) { REG* expr = new REG(); regex_yy_scan_string(regex_str.c_str()); REContext rctx = REContext{expr, domain, identifiers}; int err = yyparse(rctx); if (err != 0) { throw std::runtime_error("Cannot parse regular expression, error code " + std::to_string(err)); } return std::unique_ptr(expr); } libminizinc-2.4.2/lib/type.cpp000066400000000000000000000055041360574160400162730ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include namespace MiniZinc { std::string Type::toString(EnvI& env) const { std::ostringstream oss; if (_dim>0) { oss<<"array["; if (_enumId != 0) { const std::vector& arrayEnumIds = env.getArrayEnum(_enumId); for (unsigned int i=0; ie()->id(); } } } else { for (int i=0; i<_dim; i++) oss << (i==0 ? "" : ",") << "int"; } oss<<"] of "; } if (_dim<0) oss<<"array[$_] of "; switch (_ti) { case TI_PAR: break; case TI_VAR: oss<<"var "; break; } if (_ot==OT_OPTIONAL) oss<<"opt "; if (_st==ST_SET) oss<<"set of "; switch (_bt) { case BT_INT: { unsigned int enumId; if (_enumId != 0 && _dim > 0) { const std::vector& arrayEnumIds = env.getArrayEnum(_enumId); enumId = arrayEnumIds[arrayEnumIds.size()-1]; } else { enumId = _enumId; } if (enumId==0) { oss<<"int"; } else { oss << *env.getEnum(enumId)->e()->id(); } } break; case BT_BOOL: oss<<"bool"; break; case BT_FLOAT: oss<<"float"; break; case BT_STRING: oss<<"string"; break; case BT_ANN: oss<<"ann"; break; case BT_BOT: oss<<"bot"; break; case BT_TOP: oss<<"top"; break; case BT_UNKNOWN: oss<<"??? "; break; } return oss.str(); } std::string Type::nonEnumToString(void) const { std::ostringstream oss; if (_dim>0) { oss<<"array[int"; for (int i=1; i<_dim; i++) oss << ",int"; oss<<"] of "; } if (_dim<0) oss<<"array[$_] of "; switch (_ti) { case TI_PAR: break; case TI_VAR: oss<<"var "; break; } if (_ot==OT_OPTIONAL) oss<<"opt "; if (_st==ST_SET) oss<<"set of "; switch (_bt) { case BT_INT: oss<<"int"; break; case BT_BOOL: oss<<"bool"; break; case BT_FLOAT: oss<<"float"; break; case BT_STRING: oss<<"string"; break; case BT_ANN: oss<<"ann"; break; case BT_BOT: oss<<"bot"; break; case BT_TOP: oss<<"top"; break; case BT_UNKNOWN: oss<<"??? "; break; } return oss.str(); } } libminizinc-2.4.2/lib/typecheck.cpp000066400000000000000000003050331360574160400172710ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include #include #include #include namespace MiniZinc { Scopes::Scopes(void) { s.push_back(Scope()); s.back().toplevel = true; } void Scopes::add(EnvI &env, VarDecl *vd) { if (!s.back().toplevel && vd->ti()->isEnum() && vd->e()) { throw TypeError(env, vd->loc(), "enums are only allowed at top level"); } if (vd->id()->idn()==-1 && vd->id()->v()=="") return; DeclMap::iterator vdi = s.back().m.find(vd->id()); if (vdi == s.back().m.end()) { s.back().m.insert(vd->id(),vd); } else { GCLock lock; throw TypeError(env, vd->loc(),"identifier `"+vd->id()->str().str()+ "' already defined"); } } void Scopes::push(bool toplevel) { s.push_back(Scope()); s.back().toplevel = toplevel; } void Scopes::pop(void) { s.pop_back(); } VarDecl* Scopes::find(Id *ident) { int cur = static_cast(s.size())-1; for (;;) { DeclMap::iterator vdi = s[cur].m.find(ident); if (vdi == s[cur].m.end()) { if (s[cur].toplevel) { if (cur > 0) cur = 0; else return NULL; } else { cur--; } } else { return vdi->second; } } } struct VarDeclCmp { std::unordered_map& _pos; VarDeclCmp(std::unordered_map& pos) : _pos(pos) {} bool operator()(Expression* e0, Expression* e1) { if (VarDecl* vd0 = Expression::dyn_cast(e0)) { if (VarDecl* vd1 = Expression::dyn_cast(e1)) { return _pos[vd0] < _pos[vd1]; } else { return true; } } else { return false; } } }; struct ItemCmp { std::unordered_map& _pos; ItemCmp(std::unordered_map& pos) : _pos(pos) {} bool operator()(Item* i0, Item* i1) { if (VarDeclI* vd0 = i0->cast()) { if (VarDeclI* vd1 = i1->cast()) { return _pos[vd0->e()] < _pos[vd1->e()]; } else { return true; } } else { return false; } } }; std::string createEnumToStringName(Id* ident, std::string prefix) { std::string name = ident->str().str(); if (name[0]=='\'') { name = "'"+prefix+name.substr(1); } else { name = prefix+name; } return name; } AssignI* createEnumMapper(EnvI& env, Model* m, unsigned int enumId, VarDecl* vd, VarDecl* vd_enumToString, Model* enumItems) { Id* ident = vd->id(); SetLit* sl = vd->e()->dyn_cast(); ArrayLit* enum_init_al = NULL; AssignI* ret = NULL; GCLock lock; if (ArrayLit* al = vd->e()->dyn_cast()) { enum_init_al = al; } else if (Call* c = vd->e()->dyn_cast()) { if (c->id()!="anon_enum") { throw TypeError(env, c->loc(), "invalid initialisation for enum `"+ident->v().str()+"'"); } if (c->n_args()==1 && c->arg(0)->isa()) { enum_init_al = c->arg(0)->cast(); } } if (enum_init_al) { std::vector enumIds(enum_init_al->size()); for (unsigned int i=0; isize(); i++) { if (Id* eid = (*enum_init_al)[i]->dyn_cast()) { enumIds[i] = eid; } else { throw TypeError(env, vd->e()->loc(), "invalid initialisation for enum `"+ident->v().str()+"'"); } } sl = new SetLit(vd->e()->loc(), enumIds); } if (sl) { for (unsigned int i=0; iv().size(); i++) { if (!sl->v()[i]->isa()) { throw TypeError(env, sl->v()[i]->loc(), "invalid initialisation for enum `"+ident->v().str()+"'"); } TypeInst* ti_id = new TypeInst(sl->v()[i]->loc(),Type::parenum(enumId)); std::vector toEnumArgs(2); toEnumArgs[0] = vd->id(); toEnumArgs[1] = IntLit::a(i+1); Call* toEnum = new Call(sl->v()[i]->loc(), ASTString("to_enum"), toEnumArgs); toEnum->decl(env.model->matchFn(env, toEnum, false)); VarDecl* vd_id = new VarDecl(ti_id->loc(),ti_id,sl->v()[i]->cast()->str(),toEnum); enumItems->addItem(new VarDeclI(vd_id->loc(),vd_id)); } SetLit* nsl = new SetLit(vd->loc(), IntSetVal::a(1,sl->v().size())); Type tt = nsl->type(); tt.enumId(vd->type().enumId()); nsl->type(tt); vd->e(nsl); } else if (!vd->e()->isa()) { throw TypeError(env, vd->e()->loc(), "invalid initialisation for enum `"+ident->v().str()+"'"); } if (sl) { std::string name = createEnumToStringName(ident,"_enum_to_string_"); std::vector al_args(sl->v().size()); for (unsigned int i=0; iv().size(); i++) { std::string str = sl->v()[i]->cast()->str().str(); if (str.size()>=2 && str[0]=='\'' && str[str.size()-1]=='\'') { al_args[i] = new StringLit(Location().introduce(), ASTString(str.substr(1,str.size()-2))); } else { al_args[i] = new StringLit(Location().introduce(), ASTString(str)); } env.reverseEnum[str] = i+1; } ArrayLit* al = new ArrayLit(Location().introduce(),al_args); if (vd_enumToString) { ret = new AssignI(Location().introduce(),name,al); ret->decl(vd_enumToString); } else { std::vector ranges(1); ranges[0] = new TypeInst(Location().introduce(),Type::parint()); TypeInst* ti = new TypeInst(Location().introduce(),Type::parstring(1)); ti->setRanges(ranges); vd_enumToString = new VarDecl(Location().introduce(),ti,name,al); enumItems->addItem(new VarDeclI(Location().introduce(),vd_enumToString)); } Type tx = Type::parint(); tx.ot(Type::OT_OPTIONAL); TypeInst* ti_aa = new TypeInst(Location().introduce(),tx); VarDecl* vd_aa = new VarDecl(Location().introduce(),ti_aa,"x"); vd_aa->toplevel(false); TypeInst* ti_ab = new TypeInst(Location().introduce(),Type::parbool()); VarDecl* vd_ab = new VarDecl(Location().introduce(),ti_ab,"b"); vd_ab->toplevel(false); TypeInst* ti_aj = new TypeInst(Location().introduce(),Type::parbool()); VarDecl* vd_aj = new VarDecl(Location().introduce(),ti_aj,"json"); vd_aj->toplevel(false); TypeInst* ti_fi = new TypeInst(Location().introduce(),Type::parstring()); std::vector fi_params(3); fi_params[0] = vd_aa; fi_params[1] = vd_ab; fi_params[2] = vd_aj; std::vector deopt_args(1); deopt_args[0] = vd_aa->id(); Call* deopt = new Call(Location().introduce(), "deopt", deopt_args); Call* occurs = new Call(Location().introduce(), "occurs", deopt_args); std::vector aa_args(1); aa_args[0] = deopt; ArrayAccess* aa = new ArrayAccess(Location().introduce(),vd_enumToString->id(),aa_args); StringLit* sl_absent = new StringLit(Location().introduce(),"<>"); ITE* if_absent = new ITE(Location().introduce(), {vd_aj->id(), new StringLit(Location().introduce(), ASTString("null"))}, sl_absent); StringLit* json_e_quote = new StringLit(Location().introduce(), ASTString("{\"e\":\"")); StringLit* json_e_quote_end = new StringLit(Location().introduce(), ASTString("\"}")); BinOp* quote_aa = new BinOp(Location().introduce(),json_e_quote,BOT_PLUSPLUS,aa); BinOp* quote_aa2 = new BinOp(Location().introduce(),quote_aa,BOT_PLUSPLUS,json_e_quote_end); Call* quote_dzn = new Call(Location().introduce(),ASTString("showDznId"),{aa}); std::vector ite_ifelse(2); ite_ifelse[0] = occurs; ite_ifelse[1] = new ITE(Location().introduce(), {vd_ab->id(),quote_dzn,vd_aj->id(),quote_aa2}, aa); ITE* ite = new ITE(Location().introduce(),ite_ifelse,if_absent); FunctionI* fi = new FunctionI(Location().introduce(), createEnumToStringName(ident, "_toString_"), ti_fi,fi_params,ite); enumItems->addItem(fi); } else { if (vd_enumToString) { /// TODO: find a better solution (don't introduce the vd_enumToString until we /// know it's a non-anonymous enum) vd_enumToString->e(new ArrayLit(Location().introduce(), std::vector())); } { Type tx = Type::parint(); tx.ot(Type::OT_OPTIONAL); TypeInst* ti_aa = new TypeInst(Location().introduce(),tx); VarDecl* vd_aa = new VarDecl(Location().introduce(),ti_aa,"x"); vd_aa->toplevel(false); TypeInst* ti_ab = new TypeInst(Location().introduce(),Type::parbool()); VarDecl* vd_ab = new VarDecl(Location().introduce(),ti_ab,"b"); vd_ab->toplevel(false); TypeInst* ti_aj = new TypeInst(Location().introduce(),Type::parbool()); VarDecl* vd_aj = new VarDecl(Location().introduce(),ti_aj,"json"); vd_aj->toplevel(false); std::vector deopt_args(1); deopt_args[0] = vd_aa->id(); Call* deopt = new Call(Location().introduce(), "deopt", deopt_args); Call* if_absent = new Call(Location().introduce(), "absent", deopt_args); StringLit* sl_absent_dzn = new StringLit(Location().introduce(),"<>"); ITE* sl_absent = new ITE(Location().introduce(), {vd_aj->id(), new StringLit(Location().introduce(), ASTString("null"))}, sl_absent_dzn); StringLit* sl_dzn = new StringLit(Location().introduce(), ASTString("to_enum("+ident->str().str()+",")); std::vector showIntArgs(1); showIntArgs[0] = deopt; Call* showInt = new Call(Location().introduce(), constants().ids.show, showIntArgs); BinOp* construct_string_dzn = new BinOp(Location().introduce(), sl_dzn, BOT_PLUSPLUS, showInt); StringLit* closing_bracket = new StringLit(Location().introduce(), ASTString(")")); BinOp* construct_string_dzn_2 = new BinOp(Location().introduce(), construct_string_dzn, BOT_PLUSPLUS, closing_bracket); StringLit* sl = new StringLit(Location().introduce(), ASTString(ident->str().str()+"_")); BinOp* construct_string = new BinOp(Location().introduce(), sl, BOT_PLUSPLUS, showInt); StringLit* json_e_quote = new StringLit(Location().introduce(), ASTString("{\"e\":\"")); StringLit* json_e_quote_end = new StringLit(Location().introduce(), ASTString("\"}")); BinOp* construct_string_json = new BinOp(Location().introduce(), json_e_quote, BOT_PLUSPLUS, construct_string); BinOp* construct_string_json_2 = new BinOp(Location().introduce(), construct_string_json, BOT_PLUSPLUS, json_e_quote_end); std::vector if_then(6); if_then[0] = if_absent; if_then[1] = sl_absent; if_then[2] = vd_ab->id(); if_then[3] = construct_string_dzn_2; if_then[4] = vd_aj->id(); if_then[5] = construct_string_json_2; ITE* ite = new ITE(Location().introduce(), if_then, construct_string); TypeInst* ti_fi = new TypeInst(Location().introduce(),Type::parstring()); std::vector fi_params(3); fi_params[0] = vd_aa; fi_params[1] = vd_ab; fi_params[2] = vd_aj; FunctionI* fi = new FunctionI(Location().introduce(), createEnumToStringName(ident, "_toString_"), ti_fi,fi_params,ite); enumItems->addItem(fi); } } { /* function _toString_ENUM(array[$U] of opt Foo: x, bool: b, bool: json) = let { array[int] of opt ENUM: xx = array1d(x) } in "[" ++ join(", ", [ _toString_ENUM(xx[i],b,json) | i in index_set(xx) ]) ++ "]"; */ TIId* tiid = new TIId(Location().introduce(),"U"); TypeInst* ti_range = new TypeInst(Location().introduce(),Type::parint(),tiid); std::vector ranges(1); ranges[0] = ti_range; Type tx = Type::parint(-1); tx.ot(Type::OT_OPTIONAL); TypeInst* x_ti = new TypeInst(Location().introduce(),tx,ranges,ident); VarDecl* vd_x = new VarDecl(Location().introduce(),x_ti,"x"); vd_x->toplevel(false); TypeInst* b_ti = new TypeInst(Location().introduce(),Type::parbool()); VarDecl* vd_b = new VarDecl(Location().introduce(),b_ti,"b"); vd_b->toplevel(false); TypeInst* j_ti = new TypeInst(Location().introduce(),Type::parbool()); VarDecl* vd_j = new VarDecl(Location().introduce(),j_ti,"json"); vd_j->toplevel(false); TypeInst* xx_range = new TypeInst(Location().introduce(),Type::parint(),NULL); std::vector xx_ranges(1); xx_ranges[0] = xx_range; TypeInst* xx_ti = new TypeInst(Location().introduce(),tx,xx_ranges,ident); std::vector array1dArgs(1); array1dArgs[0] = vd_x->id(); Call* array1dCall = new Call(Location().introduce(),"array1d",array1dArgs); VarDecl* vd_xx = new VarDecl(Location().introduce(),xx_ti,"xx",array1dCall); vd_xx->toplevel(false); TypeInst* idx_i_ti = new TypeInst(Location().introduce(),Type::parint()); VarDecl* idx_i = new VarDecl(Location().introduce(),idx_i_ti,"i"); idx_i->toplevel(false); std::vector aa_xxi_idx(1); aa_xxi_idx[0] = idx_i->id(); ArrayAccess* aa_xxi = new ArrayAccess(Location().introduce(),vd_xx->id(),aa_xxi_idx); std::vector _toString_ENUMArgs(3); _toString_ENUMArgs[0] = aa_xxi; _toString_ENUMArgs[1] = vd_b->id(); _toString_ENUMArgs[2] = vd_j->id(); Call* _toString_ENUM = new Call(Location().introduce(), createEnumToStringName(ident, "_toString_"), _toString_ENUMArgs); std::vector index_set_xx_args(1); index_set_xx_args[0] = vd_xx->id(); Call* index_set_xx = new Call(Location().introduce(),"index_set",index_set_xx_args); std::vector gen_exps(1); gen_exps[0] = idx_i; Generator gen(gen_exps,index_set_xx,NULL); Generators generators; generators._g.push_back(gen); Comprehension* comp = new Comprehension(Location().introduce(),_toString_ENUM,generators,false); std::vector join_args(2); join_args[0] = new StringLit(Location().introduce(),", "); join_args[1] = comp; Call* join = new Call(Location().introduce(),"join",join_args); StringLit* sl_open = new StringLit(Location().introduce(),"["); BinOp* bopp0 = new BinOp(Location().introduce(),sl_open,BOT_PLUSPLUS,join); StringLit* sl_close = new StringLit(Location().introduce(),"]"); BinOp* bopp1 = new BinOp(Location().introduce(),bopp0,BOT_PLUSPLUS,sl_close); std::vector let_args(1); let_args[0] = vd_xx; Let* let = new Let(Location().introduce(),let_args,bopp1); TypeInst* ti_fi = new TypeInst(Location().introduce(),Type::parstring()); std::vector fi_params(3); fi_params[0] = vd_x; fi_params[1] = vd_b; fi_params[2] = vd_j; FunctionI* fi = new FunctionI(Location().introduce(), createEnumToStringName(ident, "_toString_"), ti_fi,fi_params,let); enumItems->addItem(fi); } { /* function _toString_ENUM(opt set of ENUM: x, bool: b, bool: json) = if absent(x) then "<>" else "{" ++ join(", ", [ _toString_ENUM(i,b,json) | i in x ]) ++ "}" endif; */ Type argType = Type::parsetenum(ident->type().enumId()); argType.ot(Type::OT_OPTIONAL); TypeInst* x_ti = new TypeInst(Location().introduce(),argType,ident); VarDecl* vd_x = new VarDecl(Location().introduce(),x_ti,"x"); vd_x->toplevel(false); TypeInst* b_ti = new TypeInst(Location().introduce(),Type::parbool()); VarDecl* vd_b = new VarDecl(Location().introduce(),b_ti,"b"); vd_b->toplevel(false); TypeInst* j_ti = new TypeInst(Location().introduce(),Type::parbool()); VarDecl* vd_j = new VarDecl(Location().introduce(),j_ti,"json"); vd_j->toplevel(false); TypeInst* idx_i_ti = new TypeInst(Location().introduce(),Type::parint()); VarDecl* idx_i = new VarDecl(Location().introduce(),idx_i_ti,"i"); idx_i->toplevel(false); std::vector _toString_ENUMArgs(3); _toString_ENUMArgs[0] = idx_i->id(); _toString_ENUMArgs[1] = vd_b->id(); _toString_ENUMArgs[2] = vd_j->id(); Call* _toString_ENUM = new Call(Location().introduce(), createEnumToStringName(ident, "_toString_"), _toString_ENUMArgs); std::vector deopt_args(1); deopt_args[0] = vd_x->id(); Call* deopt = new Call(Location().introduce(), "deopt", deopt_args); Call* if_absent = new Call(Location().introduce(), "absent", deopt_args); StringLit* sl_absent_dzn = new StringLit(Location().introduce(),"<>"); ITE* sl_absent = new ITE(Location().introduce(), {vd_j->id(), new StringLit(Location().introduce(), ASTString("null"))}, sl_absent_dzn); std::vector gen_exps(1); gen_exps[0] = idx_i; Generator gen(gen_exps,deopt,NULL); Generators generators; generators._g.push_back(gen); Comprehension* comp = new Comprehension(Location().introduce(),_toString_ENUM,generators,false); std::vector join_args(2); join_args[0] = new StringLit(Location().introduce(),", "); join_args[1] = comp; Call* join = new Call(Location().introduce(),"join",join_args); ITE* json_set = new ITE(Location().introduce(), {vd_j->id(), new StringLit(Location().introduce(),ASTString("\"set\":["))}, new StringLit(Location().introduce(),ASTString(""))); ITE* json_set_close = new ITE(Location().introduce(), {vd_j->id(), new StringLit(Location().introduce(),ASTString("]"))}, new StringLit(Location().introduce(),ASTString(""))); StringLit* sl_open = new StringLit(Location().introduce(),"{"); BinOp* bopp0 = new BinOp(Location().introduce(),sl_open,BOT_PLUSPLUS,json_set); BinOp* bopp1 = new BinOp(Location().introduce(),bopp0,BOT_PLUSPLUS,join); BinOp* bopp2 = new BinOp(Location().introduce(),bopp1,BOT_PLUSPLUS,json_set_close); StringLit* sl_close = new StringLit(Location().introduce(),"}"); BinOp* bopp3 = new BinOp(Location().introduce(),bopp2,BOT_PLUSPLUS,sl_close); std::vector if_then(2); if_then[0] = if_absent; if_then[1] = sl_absent; ITE* ite = new ITE(Location().introduce(), if_then, bopp3); TypeInst* ti_fi = new TypeInst(Location().introduce(),Type::parstring()); std::vector fi_params(3); fi_params[0] = vd_x; fi_params[1] = vd_b; fi_params[2] = vd_j; FunctionI* fi = new FunctionI(Location().introduce(), createEnumToStringName(ident, "_toString_"), ti_fi,fi_params,ite); enumItems->addItem(fi); } { /* function _toString_ENUM(array[$U] of opt set of ENUM: x, bool: b, bool: json) = let { array[int] of opt set of ENUM: xx = array1d(x) } in "[" ++ join(", ", [ _toString_ENUM(xx[i],b,json) | i in index_set(xx) ]) ++ "]"; */ TIId* tiid = new TIId(Location().introduce(),"U"); TypeInst* ti_range = new TypeInst(Location().introduce(),Type::parint(),tiid); std::vector ranges(1); ranges[0] = ti_range; Type tx = Type::parsetint(-1); tx.ot(Type::OT_OPTIONAL); TypeInst* x_ti = new TypeInst(Location().introduce(),tx,ranges,ident); VarDecl* vd_x = new VarDecl(Location().introduce(),x_ti,"x"); vd_x->toplevel(false); TypeInst* b_ti = new TypeInst(Location().introduce(),Type::parbool()); VarDecl* vd_b = new VarDecl(Location().introduce(),b_ti,"b"); vd_b->toplevel(false); TypeInst* j_ti = new TypeInst(Location().introduce(),Type::parbool()); VarDecl* vd_j = new VarDecl(Location().introduce(),j_ti,"json"); vd_j->toplevel(false); TypeInst* xx_range = new TypeInst(Location().introduce(),Type::parint(),NULL); std::vector xx_ranges(1); xx_ranges[0] = xx_range; TypeInst* xx_ti = new TypeInst(Location().introduce(),tx,xx_ranges,ident); std::vector array1dArgs(1); array1dArgs[0] = vd_x->id(); Call* array1dCall = new Call(Location().introduce(),"array1d",array1dArgs); VarDecl* vd_xx = new VarDecl(Location().introduce(),xx_ti,"xx",array1dCall); vd_xx->toplevel(false); TypeInst* idx_i_ti = new TypeInst(Location().introduce(),Type::parint()); VarDecl* idx_i = new VarDecl(Location().introduce(),idx_i_ti,"i"); idx_i->toplevel(false); std::vector aa_xxi_idx(1); aa_xxi_idx[0] = idx_i->id(); ArrayAccess* aa_xxi = new ArrayAccess(Location().introduce(),vd_xx->id(),aa_xxi_idx); std::vector _toString_ENUMArgs(3); _toString_ENUMArgs[0] = aa_xxi; _toString_ENUMArgs[1] = vd_b->id(); _toString_ENUMArgs[2] = vd_j->id(); Call* _toString_ENUM = new Call(Location().introduce(), createEnumToStringName(ident, "_toString_"), _toString_ENUMArgs); std::vector index_set_xx_args(1); index_set_xx_args[0] = vd_xx->id(); Call* index_set_xx = new Call(Location().introduce(),"index_set",index_set_xx_args); std::vector gen_exps(1); gen_exps[0] = idx_i; Generator gen(gen_exps,index_set_xx,NULL); Generators generators; generators._g.push_back(gen); Comprehension* comp = new Comprehension(Location().introduce(),_toString_ENUM,generators,false); std::vector join_args(2); join_args[0] = new StringLit(Location().introduce(),", "); join_args[1] = comp; Call* join = new Call(Location().introduce(),"join",join_args); StringLit* sl_open = new StringLit(Location().introduce(),"["); BinOp* bopp0 = new BinOp(Location().introduce(),sl_open,BOT_PLUSPLUS,join); StringLit* sl_close = new StringLit(Location().introduce(),"]"); BinOp* bopp1 = new BinOp(Location().introduce(),bopp0,BOT_PLUSPLUS,sl_close); std::vector let_args(1); let_args[0] = vd_xx; Let* let = new Let(Location().introduce(),let_args,bopp1); TypeInst* ti_fi = new TypeInst(Location().introduce(),Type::parstring()); std::vector fi_params(3); fi_params[0] = vd_x; fi_params[1] = vd_b; fi_params[2] = vd_j; FunctionI* fi = new FunctionI(Location().introduce(), createEnumToStringName(ident, "_toString_"), ti_fi,fi_params,let); enumItems->addItem(fi); } return ret; } void TopoSorter::add(EnvI& env, VarDeclI* vdi, bool handleEnums, Model* enumItems) { VarDecl* vd = vdi->e(); if (handleEnums && vd->ti()->isEnum()) { unsigned int enumId = env.registerEnum(vdi); Type vdt = vd->type(); vdt.enumId(enumId); vd->ti()->type(vdt); vd->type(vdt); if (vd->e()) { (void) createEnumMapper(env, model, enumId, vd, NULL, enumItems); } else { GCLock lock; std::string name = createEnumToStringName(vd->id(),"_enum_to_string_"); std::vector ranges(1); ranges[0] = new TypeInst(Location().introduce(),Type::parint()); TypeInst* ti = new TypeInst(Location().introduce(),Type::parstring(1)); ti->setRanges(ranges); VarDecl* vd_enumToString = new VarDecl(Location().introduce(),ti,name,NULL); enumItems->addItem(new VarDeclI(Location().introduce(),vd_enumToString)); } } scopes.add(env, vd); } VarDecl* TopoSorter::get(EnvI& env, const ASTString& id_v, const Location& loc) { GCLock lock; Id* id = new Id(Location(), id_v, NULL); VarDecl* decl = scopes.find(id); if (decl==NULL) { throw TypeError(env,loc,"undefined identifier `"+id->str().str()+"'"); } return decl; } VarDecl* TopoSorter::checkId(EnvI& env, Id* ident, const Location& loc) { VarDecl* decl = scopes.find(ident); if (decl==NULL) { GCLock lock; throw TypeError(env,loc,"undefined identifier `"+ident->str().str()+"'"); } PosMap::iterator pi = pos.find(decl); if (pi==pos.end()) { // new id scopes.push(true); run(env, decl); scopes.pop(); } else { // previously seen, check if circular if (pi->second==-1) { GCLock lock; throw TypeError(env,loc,"circular definition of `"+ident->str().str()+"'"); } } return decl; } VarDecl* TopoSorter::checkId(EnvI& env, const ASTString& id_v, const Location& loc) { GCLock lock; Id* id = new Id(loc,id_v,NULL); return checkId(env, id, loc); } void TopoSorter::run(EnvI& env, Expression* e) { if (e==NULL) return; switch (e->eid()) { case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_BOOLLIT: case Expression::E_STRINGLIT: case Expression::E_ANON: break; case Expression::E_SETLIT: { SetLit* sl = e->cast(); if(sl->isv()==NULL && sl->fsv()==NULL) for (unsigned int i=0; iv().size(); i++) run(env,sl->v()[i]); } break; case Expression::E_ID: { if (e != constants().absent) { VarDecl* vd = checkId(env, e->cast(),e->loc()); e->cast()->decl(vd); } } break; case Expression::E_ARRAYLIT: { ArrayLit* al = e->cast(); for (unsigned int i=0; isize(); i++) run(env, (*al)[i]); } break; case Expression::E_ARRAYACCESS: { ArrayAccess* ae = e->cast(); run(env, ae->v()); for (unsigned int i=0; iidx().size(); i++) run(env, ae->idx()[i]); } break; case Expression::E_COMP: { Comprehension* ce = e->cast(); scopes.push(false); for (int i=0; in_generators(); i++) { run(env, ce->in(i)); for (int j=0; jn_decls(i); j++) { run(env, ce->decl(i,j)); scopes.add(env, ce->decl(i,j)); } if (ce->where(i)) run(env, ce->where(i)); } run(env, ce->e()); scopes.pop(); } break; case Expression::E_ITE: { ITE* ite = e->cast(); for (int i=0; isize(); i++) { run(env, ite->e_if(i)); run(env, ite->e_then(i)); } run(env, ite->e_else()); } break; case Expression::E_BINOP: { BinOp* be = e->cast(); std::vector todo; todo.push_back(be->lhs()); todo.push_back(be->rhs()); while (!todo.empty()) { Expression* e = todo.back(); todo.pop_back(); if (BinOp* e_bo = e->dyn_cast()) { todo.push_back(e_bo->lhs()); todo.push_back(e_bo->rhs()); for (ExpressionSetIter it = e_bo->ann().begin(); it != e_bo->ann().end(); ++it) run(env, *it); } else { run(env, e); } } } break; case Expression::E_UNOP: { UnOp* ue = e->cast(); run(env, ue->e()); } break; case Expression::E_CALL: { Call* ce = e->cast(); for (unsigned int i=0; in_args(); i++) run(env, ce->arg(i)); } break; case Expression::E_VARDECL: { VarDecl* ve = e->cast(); PosMap::iterator pi = pos.find(ve); if (pi==pos.end()) { pos.insert(std::pair(ve,-1)); run(env, ve->ti()); run(env, ve->e()); ve->payload(static_cast(decls.size())); decls.push_back(ve); pi = pos.find(ve); pi->second = static_cast(decls.size())-1; } else { assert(pi->second != -1); } } break; case Expression::E_TI: { TypeInst* ti = e->cast(); for (unsigned int i=0; iranges().size(); i++) run(env, ti->ranges()[i]); run(env, ti->domain()); } break; case Expression::E_TIID: break; case Expression::E_LET: { Let* let = e->cast(); scopes.push(false); for (unsigned int i=0; ilet().size(); i++) { run(env, let->let()[i]); if (VarDecl* vd = let->let()[i]->dyn_cast()) { scopes.add(env, vd); } } run(env, let->in()); VarDeclCmp poscmp(pos); std::stable_sort(let->let().begin(), let->let().end(), poscmp); for (unsigned int i=0, j=0; ilet().size(); i++) { if (VarDecl* vd = let->let()[i]->dyn_cast()) { let->let_orig()[j++] = vd->e(); for (unsigned int k=0; kti()->ranges().size(); k++) { let->let_orig()[j++] = vd->ti()->ranges()[k]->domain(); } } } scopes.pop(); } break; } if (env.ignoreUnknownIds) { std::vector toDelete; for (ExpressionSetIter it = e->ann().begin(); it != e->ann().end(); ++it) { try { run(env, *it); } catch (TypeError&) { toDelete.push_back(*it); } for (Expression* de : toDelete) e->ann().remove(de); } } else { for (ExpressionSetIter it = e->ann().begin(); it != e->ann().end(); ++it) { run(env, *it); } } } KeepAlive addCoercion(EnvI& env, Model* m, Expression* e, const Type& funarg_t) { if (e->isa() && e->type().dim() > 0) { ArrayAccess* aa = e->cast(); // Turn ArrayAccess into a slicing operation std::vector args; args.push_back(aa->v()); args.push_back(NULL); std::vector slice; GCLock lock; for (unsigned int i=0; iidx().size(); i++) { if (aa->idx()[i]->type().is_set()) { bool needIdxSet = true; bool needInter = true; if (SetLit* sl = aa->idx()[i]->dyn_cast()) { if (sl->isv() && sl->isv()->size()==1) { if (sl->isv()->min().isFinite() && sl->isv()->max().isFinite()) { args.push_back(sl); needIdxSet = false; } else if (sl->isv()->min()==-IntVal::infinity() && sl->isv()->max()==IntVal::infinity()) { needInter = false; } } } if (needIdxSet) { std::ostringstream oss; oss << "index_set"; if (aa->idx().size()>1) { oss << "_" << (i+1) << "of" << aa->idx().size(); } std::vector origIdxsetArgs(1); origIdxsetArgs[0] = aa->v(); Call* origIdxset = new Call(aa->v()->loc(), ASTString(oss.str()), origIdxsetArgs); FunctionI* fi = m->matchFn(env, origIdxset, false); if (!fi) throw TypeError(env, e->loc(), "missing builtin "+oss.str()); origIdxset->type(fi->rtype(env, origIdxsetArgs, false)); origIdxset->decl(fi); if (needInter) { BinOp* inter = new BinOp(aa->idx()[i]->loc(), aa->idx()[i], BOT_INTERSECT, origIdxset); inter->type(Type::parsetint()); args.push_back(inter); } else { args.push_back(origIdxset); } } slice.push_back(aa->idx()[i]); } else { BinOp* bo = new BinOp(aa->idx()[i]->loc(),aa->idx()[i],BOT_DOTDOT,aa->idx()[i]); bo->type(Type::parsetint()); slice.push_back(bo); } } ArrayLit* a_slice = new ArrayLit(e->loc(), slice); a_slice->type(Type::parsetint(1)); args[1] = a_slice; std::ostringstream oss; oss << "slice_" << (args.size()-2) << "d"; Call* c = new Call(e->loc(), ASTString(oss.str()), args); FunctionI* fi = m->matchFn(env, c, false); if (!fi) throw TypeError(env, e->loc(), "missing builtin "+oss.str()); c->type(fi->rtype(env, args, false)); c->decl(fi); e = c; } if (e->type().dim()==funarg_t.dim() && (funarg_t.bt()==Type::BT_BOT || funarg_t.bt()==Type::BT_TOP || e->type().bt()==funarg_t.bt() || e->type().bt()==Type::BT_BOT)) return e; std::vector args(1); args[0] = e; GCLock lock; Call* c = NULL; if (e->type().dim()==0 && funarg_t.dim()!=0) { if (e->type().isvar()) { throw TypeError(env, e->loc(),"cannot coerce var set into array"); } if (e->type().isopt()) { throw TypeError(env, e->loc(),"cannot coerce opt set into array"); } std::vector set2a_args(1); set2a_args[0] = e; Call* set2a = new Call(e->loc(), ASTString("set2array"), set2a_args); FunctionI* fi = m->matchFn(env, set2a, false); if (fi) { set2a->type(fi->rtype(env, args, false)); set2a->decl(fi); e = set2a; } } if (funarg_t.bt()==Type::BT_TOP || e->type().bt()==funarg_t.bt() || e->type().bt()==Type::BT_BOT) { KeepAlive ka(e); return ka; } if (e->type().bt()==Type::BT_BOOL) { if (funarg_t.bt()==Type::BT_INT) { c = new Call(e->loc(), constants().ids.bool2int, args); } else if (funarg_t.bt()==Type::BT_FLOAT) { c = new Call(e->loc(), constants().ids.bool2float, args); } } else if (e->type().bt()==Type::BT_INT) { if (funarg_t.bt()==Type::BT_FLOAT) { c = new Call(e->loc(), constants().ids.int2float, args); } } if (c) { FunctionI* fi = m->matchFn(env, c, false); assert(fi); c->type(fi->rtype(env, args, false)); c->decl(fi); KeepAlive ka(c); return ka; } throw TypeError(env, e->loc(),"cannot determine coercion from type "+e->type().toString(env)+" to type "+funarg_t.toString(env)); } KeepAlive addCoercion(EnvI& env, Model* m, Expression* e, Expression* funarg) { return addCoercion(env, m, e, funarg->type()); } template class Typer { public: EnvI& _env; Model* _model; std::vector& _typeErrors; bool _ignoreUndefined; Typer(EnvI& env, Model* model, std::vector& typeErrors, bool ignoreUndefined) : _env(env), _model(model), _typeErrors(typeErrors), _ignoreUndefined(ignoreUndefined) {} /// Check annotations when expression is finished void exit(Expression* e) { for (ExpressionSetIter it = e->ann().begin(); it != e->ann().end(); ++it) if (!(*it)->type().isann()) throw TypeError(_env,(*it)->loc(),"expected annotation, got `"+(*it)->type().toString(_env)+"'"); } bool enter(Expression*) { return true; } /// Visit integer literal void vIntLit(const IntLit&) {} /// Visit floating point literal void vFloatLit(const FloatLit&) {} /// Visit Boolean literal void vBoolLit(const BoolLit&) {} /// Visit set literal void vSetLit(SetLit& sl) { Type ty; ty.st(Type::ST_SET); if (sl.isv()) { ty.bt(Type::BT_INT); ty.enumId(sl.type().enumId()); sl.type(ty); return; } unsigned int enumId = sl.v().size() > 0 ? sl.v()[0]->type().enumId() : 0; for (unsigned int i=0; itype().dim() > 0) throw TypeError(_env,sl.v()[i]->loc(),"set literals cannot contain arrays"); if (sl.v()[i]->type().isvar()) ty.ti(Type::TI_VAR); if (sl.v()[i]->type().isopt()) throw TypeError(_env,sl.v()[i]->loc(),"set literals cannot contain option type values"); if (sl.v()[i]->type().cv()) ty.cv(true); if (enumId != sl.v()[i]->type().enumId()) enumId = 0; if (!Type::bt_subtype(sl.v()[i]->type(), ty, true)) { if (ty.bt() == Type::BT_UNKNOWN || Type::bt_subtype(ty, sl.v()[i]->type(), true)) { ty.bt(sl.v()[i]->type().bt()); } else { throw TypeError(_env,sl.loc(),"non-uniform set literal"); } } } ty.enumId(enumId); if (ty.bt() == Type::BT_UNKNOWN) { ty.bt(Type::BT_BOT); } else { if (ty.isvar() && ty.bt()!=Type::BT_INT) { if (ty.bt()==Type::BT_BOOL) ty.bt(Type::BT_INT); else throw TypeError(_env,sl.loc(),"cannot coerce set literal element to var int"); } for (unsigned int i=0; itype().isunknown()); id.type(id.decl()->type()); } } /// Visit anonymous variable void vAnonVar(const AnonVar&) {} /// Visit array literal void vArrayLit(ArrayLit& al) { Type ty; ty.dim(al.dims()); std::vector anons; bool haveAbsents = false; bool haveInferredType = false; for (unsigned int i=0; itype().dim() > 0) throw TypeError(_env,vi->loc(),"arrays cannot be elements of arrays"); if (vi == constants().absent) haveAbsents = true; AnonVar* av = vi->dyn_cast(); if (av) { ty.ti(Type::TI_VAR); anons.push_back(av); } else if (vi->type().isvar()) { ty.ti(Type::TI_VAR); } if (vi->type().cv()) ty.cv(true); if (vi->type().isopt()) { ty.ot(Type::OT_OPTIONAL); } if (ty.bt()==Type::BT_UNKNOWN) { if (av == NULL) { if (haveInferredType) { if (ty.st() != vi->type().st() && vi->type().ot()!=Type::OT_OPTIONAL) { throw TypeError(_env,al.loc(),"non-uniform array literal"); } } else { haveInferredType = true; ty.st(vi->type().st()); } if (vi->type().bt() != Type::BT_BOT) { ty.bt(vi->type().bt()); ty.enumId(vi->type().enumId()); } } } else { if (av == NULL) { if (vi->type().bt() == Type::BT_BOT) { if (vi->type().st() != ty.st() && vi->type().ot()!=Type::OT_OPTIONAL) { throw TypeError(_env,al.loc(),"non-uniform array literal"); } if (vi->type().enumId() != 0 && ty.enumId() != vi->type().enumId()) { ty.enumId(0); } } else { unsigned int tyEnumId = ty.enumId(); ty.enumId(vi->type().enumId()); if (Type::bt_subtype(ty, vi->type(), true)) { ty.bt(vi->type().bt()); } if (tyEnumId != vi->type().enumId()) ty.enumId(0); if (!Type::bt_subtype(vi->type(),ty,true) || ty.st() != vi->type().st()) { throw TypeError(_env,al.loc(),"non-uniform array literal"); } } } } } if (ty.bt() == Type::BT_UNKNOWN) { ty.bt(Type::BT_BOT); if (!anons.empty()) throw TypeError(_env,al.loc(),"array literal must contain at least one non-anonymous variable"); if (haveAbsents) throw TypeError(_env,al.loc(),"array literal must contain at least one non-absent value"); } else { Type at = ty; at.dim(0); if (at.ti()==Type::TI_VAR && at.st()==Type::ST_SET && at.bt()!=Type::BT_INT) { if (at.bt()==Type::BT_BOOL) { ty.bt(Type::BT_INT); at.bt(Type::BT_INT); } else { throw TypeError(_env,al.loc(),"cannot coerce array element to var set of int"); } } for (unsigned int i=0; itype(at); } for (unsigned int i=0; i enumIds(ty.dim()+1); for (int i=0; itype().dim()==0) { if (aa.v()->type().st() == Type::ST_SET) { Type tv = aa.v()->type(); tv.st(Type::ST_PLAIN); tv.dim(1); aa.v(addCoercion(_env, _model, aa.v(), tv)()); } else { std::ostringstream oss; oss << "array access attempted on expression of type `" << aa.v()->type().toString(_env) << "'"; throw TypeError(_env,aa.v()->loc(),oss.str()); } } else if (aa.v()->isa()) { aa.v(addCoercion(_env, _model, aa.v(), aa.v()->type())()); } if (aa.v()->type().dim() != aa.idx().size()) { std::ostringstream oss; oss << aa.v()->type().dim() << "-dimensional array accessed with " << aa.idx().size() << (aa.idx().size()==1 ? " expression" : " expressions"); throw TypeError(_env,aa.v()->loc(),oss.str()); } Type tt = aa.v()->type(); if (tt.enumId() != 0) { const std::vector& arrayEnumIds = _env.getArrayEnum(tt.enumId()); for (unsigned int i=0; idyn_cast()) { if (IntSetVal* aai_isv = aai_sl->isv()) { if (aai_isv->min()==-IntVal::infinity() && aai_isv->max()==IntVal::infinity()) { Type aai_sl_t = aai_sl->type(); aai_sl_t.enumId(arrayEnumIds[i]); aai_sl->type(aai_sl_t); } } } else if (BinOp* aai_bo = aai->dyn_cast()) { if (aai_bo->op()==BOT_DOTDOT) { Type aai_bo_t = aai_bo->type(); if (IntLit* il = aai_bo->lhs()->dyn_cast()) { if (il->v()==-IntVal::infinity()) { // Expression is ..X, so result gets enum type of X aai_bo_t.enumId(aai_bo->rhs()->type().enumId()); } } else if (IntLit* il = aai_bo->rhs()->dyn_cast()) { if (il->v()==IntVal::infinity()) { // Expression is X.., so result gets enum type of X aai_bo_t.enumId(aai_bo->lhs()->type().enumId()); } } aai_bo->type(aai_bo_t); } } if (arrayEnumIds[i] != 0) { if (aa.idx()[i]->type().enumId() != arrayEnumIds[i]) { std::ostringstream oss; oss << "array index "; if (aa.idx().size() > 1) { oss << (i+1) << " "; } oss << "must be `" << _env.getEnum(arrayEnumIds[i])->e()->id()->str().str() << "', but is `" << aa.idx()[i]->type().toString(_env) << "'"; throw TypeError(_env,aa.loc(),oss.str()); } } } tt.enumId(arrayEnumIds[arrayEnumIds.size()-1]); } int n_dimensions = 0; bool isVarAccess = false; bool isSlice = false; for (unsigned int i=0; iisa()) { aai->type(Type::varint()); } if ((aai->type().bt() != Type::BT_INT && aai->type().bt() != Type::BT_BOOL) || aai->type().dim() != 0) { throw TypeError(_env,aa.loc(),"array index must be `int' or `set of int', but is `"+aai->type().toString(_env)+"'"); } if (aai->type().is_set()) { if (isVarAccess || aai->type().isvar()) { throw TypeError(_env,aa.loc(),"array slicing with variable range or index not supported"); } isSlice = true; aa.idx()[i] = addCoercion(_env, _model, aai, Type::varsetint())(); n_dimensions++; } else { aa.idx()[i] = addCoercion(_env, _model, aai, Type::varint())(); } if (aai->type().isopt()) { tt.ot(Type::OT_OPTIONAL); } if (aai->type().isvar()) { isVarAccess = true; if (isSlice) { throw TypeError(_env,aa.loc(),"array slicing with variable range or index not supported"); } tt.ti(Type::TI_VAR); if (tt.bt()==Type::BT_ANN || tt.bt()==Type::BT_STRING) { throw TypeError(_env,aai->loc(),std::string("array access using a variable not supported for array of ")+(tt.bt()==Type::BT_ANN ? "ann" : "string")); } } tt.dim(n_dimensions); if (aai->type().cv()) tt.cv(true); } aa.type(tt); } /// Visit array comprehension void vComprehension(Comprehension& c) { Type tt = c.e()->type(); typedef std::unordered_map > genMap_t; typedef std::unordered_map > whereMap_t; genMap_t generatorMap; whereMap_t whereMap; int declCount = 0; bool didMoveWheres = false; for (int i=0; i(i,declCount++); whereMap[c.decl(i,j)] = std::vector(); } Expression* g_in = c.in(i); if (g_in) { const Type& ty_in = g_in->type(); if (ty_in == Type::varsetint()) { tt.ot(Type::OT_OPTIONAL); tt.ti(Type::TI_VAR); tt.cv(true); } if (ty_in.cv()) tt.cv(true); if (c.where(i)) { if (c.where(i)->type() == Type::varbool()) { tt.ot(Type::OT_OPTIONAL); tt.ti(Type::TI_VAR); tt.cv(true); } else if (c.where(i)->type() != Type::parbool()) { throw TypeError(_env,c.where(i)->loc(), "where clause must be bool, but is `"+ c.where(i)->type().toString(_env)+"'"); } if (c.where(i)->type().cv()) tt.cv(true); // Try to move parts of the where clause to earlier generators std::vector wherePartsStack; std::vector whereParts; wherePartsStack.push_back(c.where(i)); while (!wherePartsStack.empty()) { Expression* e = wherePartsStack.back(); wherePartsStack.pop_back(); if (BinOp* bo = e->dyn_cast()) { if (bo->op()==BOT_AND) { wherePartsStack.push_back(bo->rhs()); wherePartsStack.push_back(bo->lhs()); } else { whereParts.push_back(e); } } else { whereParts.push_back(e); } } for (unsigned int wpi=0; wpi < whereParts.size(); wpi++) { Expression* wp = whereParts[wpi]; class FindLatestGen : public EVisitor { public: int decl_idx; VarDecl* decl; const genMap_t& generatorMap; Comprehension* comp; FindLatestGen(const genMap_t& generatorMap0, Comprehension* comp0) : decl_idx(-1), decl(comp0->decl(0,0)), generatorMap(generatorMap0), comp(comp0) {} void vId(const Id& ident) { genMap_t::const_iterator it = generatorMap.find(ident.decl()); if (it != generatorMap.end() && it->second.second > decl_idx) { decl_idx = it->second.second; decl = ident.decl(); int gen = it->second.first; while (comp->in(gen) == NULL && gen < comp->n_generators()-1) { decl_idx++; gen++; decl = comp->decl(gen, 0); } } } } flg(generatorMap,&c); topDown(flg, wp); whereMap[flg.decl].push_back(wp); if (flg.decl_idx < declCount-1) didMoveWheres = true; } } } else { assert(c.where(i) != NULL); whereMap[c.decl(i,0)].push_back(c.where(i)); } } if (didMoveWheres) { Generators generators; for (int i=0; i decls; for (int j=0; jtype().ispar() && whereExpr->type().ispar() ? Type::parbool() : Type::varbool(); bo->type(bo_t); whereExpr = bo; } generators._g.push_back(Generator(decls,c.in(i),whereExpr)); decls.clear(); } else if (j==c.n_decls(i)-1) { generators._g.push_back(Generator(decls,c.in(i),NULL)); decls.clear(); } } } GCLock lock; c.init(c.e(), generators); } if (c.set()) { if (c.e()->type().dim() != 0 || c.e()->type().st() == Type::ST_SET) throw TypeError(_env,c.e()->loc(), "set comprehension expression must be scalar, but is `" +c.e()->type().toString(_env)+"'"); tt.st(Type::ST_SET); if (tt.isvar()) { c.e(addCoercion(_env, _model, c.e(), Type::varint())()); tt.bt(Type::BT_INT); } } else { if (c.e()->type().dim() != 0) throw TypeError(_env,c.e()->loc(), "array comprehension expression cannot be an array"); tt.dim(1); if (tt.enumId() != 0) { std::vector enumIds(2); enumIds[0] = 0; enumIds[1] = tt.enumId(); tt.enumId(_env.registerArrayEnum(enumIds)); } } c.type(tt); } /// Visit array comprehension generator void vComprehensionGenerator(Comprehension& c, int gen_i) { Expression* g_in = c.in(gen_i); if (g_in==NULL) { // This is an "assignment generator" (i = expr) assert(c.where(gen_i) != NULL); assert(c.n_decls(gen_i) == 1); const Type& ty_where = c.where(gen_i)->type(); c.decl(gen_i,0)->type(ty_where); c.decl(gen_i,0)->ti()->type(ty_where); } else { const Type& ty_in = g_in->type(); if (ty_in != Type::varsetint() && ty_in != Type::parsetint() && ty_in.dim() != 1) { throw TypeError(_env,g_in->loc(), "generator expression must be (par or var) set of int or one-dimensional array, but is `" +ty_in.toString(_env)+"'"); } Type ty_id; bool needIntLit = false; if (ty_in.dim()==0) { ty_id = Type::parint(); ty_id.enumId(ty_in.enumId()); needIntLit = true; } else { ty_id = ty_in; if (ty_in.enumId() != 0) { const std::vector& enumIds = _env.getArrayEnum(ty_in.enumId()); ty_id.enumId(enumIds.back()); } ty_id.dim(0); } for (int j=0; je(IntLit::aEnum(0,ty_id.enumId())); } c.decl(gen_i,j)->type(ty_id); c.decl(gen_i,j)->ti()->type(ty_id); } } } /// Visit if-then-else void vITE(ITE& ite) { bool mustBeBool = false; if (ite.e_else()==NULL) { // this is an "if then endif" so the must be bool ite.e_else(constants().boollit(true)); mustBeBool = true; } Type tret = ite.e_else()->type(); std::vector anons; bool allpar = !(tret.isvar()); if (tret.isunknown()) { if (AnonVar* av = ite.e_else()->dyn_cast()) { allpar = false; anons.push_back(av); } else { throw TypeError(_env,ite.e_else()->loc(), "cannot infer type of expression in `else' branch of conditional"); } } bool allpresent = !(tret.isopt()); bool varcond = false; for (int i=0; itype() == Type::varbool()); if (eif->type() != Type::parbool() && eif->type() != Type::varbool()) throw TypeError(_env,eif->loc(), "expected bool conditional expression, got `"+ eif->type().toString(_env)+"'"); if (eif->type().cv()) tret.cv(true); if (ethen->type().isunknown()) { if (AnonVar* av = ethen->dyn_cast()) { allpar = false; anons.push_back(av); } else { throw TypeError(_env,ethen->loc(), "cannot infer type of expression in `then' branch of conditional"); } } else { if (tret.isbot() || tret.isunknown()) tret.bt(ethen->type().bt()); if (mustBeBool && (ethen->type().bt() != Type::BT_BOOL || ethen->type().dim() > 0 || ethen->type().st() != Type::ST_PLAIN || ethen->type().ot() != Type::OT_PRESENT)) { throw TypeError(_env,ite.loc(), std::string("conditional without `else' branch must have bool type, ")+ "but `then' branch has type `"+ethen->type().toString(_env)+"'"); } if ( (!ethen->type().isbot() && !Type::bt_subtype(ethen->type(), tret, true) && !Type::bt_subtype(tret, ethen->type(), true)) || ethen->type().st() != tret.st() || ethen->type().dim() != tret.dim()) { throw TypeError(_env,ethen->loc(), "type mismatch in branches of conditional. `then' branch has type `"+ ethen->type().toString(_env)+"', but `else' branch has type `"+ tret.toString(_env)+"'"); } if (Type::bt_subtype(tret, ethen->type(), true)) { tret.bt(ethen->type().bt()); } if (tret.enumId()!=0 && ethen->type().enumId()==0) { tret.enumId(0); } if (ethen->type().isvar()) allpar=false; if (ethen->type().isopt()) allpresent=false; if (ethen->type().cv()) tret.cv(true); } } Type tret_var(tret); tret_var.ti(Type::TI_VAR); for (unsigned int i=0; itype(tret_var); } for (int i=0; i 0) throw TypeError(_env,ite.loc(), "conditional with var condition cannot have array type"); if (varcond || !allpar) tret.ti(Type::TI_VAR); if (!allpresent) tret.ot(Type::OT_OPTIONAL); ite.type(tret); } /// Visit binary operator void vBinOp(BinOp& bop) { std::vector args(2); args[0] = bop.lhs(); args[1] = bop.rhs(); if (FunctionI* fi = _model->matchFn(_env,bop.opToString(),args,true)) { bop.lhs(addCoercion(_env, _model,bop.lhs(),fi->argtype(_env,args, 0))()); bop.rhs(addCoercion(_env, _model,bop.rhs(),fi->argtype(_env,args, 1))()); args[0] = bop.lhs(); args[1] = bop.rhs(); Type ty = fi->rtype(_env,args,true); ty.cv(bop.lhs()->type().cv() || bop.rhs()->type().cv()); bop.type(ty); if (fi->e()) bop.decl(fi); else bop.decl(NULL); if (bop.lhs()->type().isint() && bop.rhs()->type().isint() && (bop.op()==BOT_EQ || bop.op()==BOT_GQ || bop.op()==BOT_GR || bop.op()==BOT_NQ || bop.op()==BOT_LE || bop.op()==BOT_LQ)) { Call* call = bop.lhs()->dyn_cast(); Expression* rhs = bop.rhs(); BinOpType bot = bop.op(); if (!call) { call = bop.rhs()->dyn_cast(); rhs = bop.lhs(); switch (bop.op()) { case BOT_LQ: bot=BOT_GQ; break; case BOT_LE: bot=BOT_GR; break; case BOT_GQ: bot=BOT_LQ; break; case BOT_GR: bot=BOT_LE; break; default: break; } } if (call && (call->id()=="count" || call->id()=="sum") && call->type().isvar()) { if (call->n_args()==1 && call->arg(0)->isa()) { Comprehension* comp = call->arg(0)->cast(); BinOp* inner_bo = comp->e()->dyn_cast(); if (inner_bo) { if (inner_bo->op()==BOT_EQ && inner_bo->lhs()->type().isint()) { Expression* generated = inner_bo->lhs(); Expression* comparedTo = inner_bo->rhs(); if (comp->containsBoundVariable(comparedTo)) { if (comp->containsBoundVariable(generated)) { comparedTo = nullptr; } else { std::swap(generated,comparedTo); } } if (comparedTo) { GCLock lock; ASTString cid; switch (bot) { case BOT_EQ: cid = ASTString("count_eq"); break; case BOT_GQ: cid = ASTString("count_leq"); break; case BOT_GR: cid = ASTString("count_lt"); break; case BOT_LQ: cid = ASTString("count_geq"); break; case BOT_LE: cid = ASTString("count_gt"); break; case BOT_NQ: cid = ASTString("count_neq"); break; default: assert(false); } comp->e(generated); Type ct = comp->type(); ct.bt(generated->type().bt()); comp->type(ct); std::vector args({comp,comparedTo,rhs}); FunctionI* newCall_decl = _model->matchFn(_env, cid, args, true); if (newCall_decl==nullptr) { throw InternalError("could not replace binary operator by call to "+cid.str()); } else { Call* newCall = bop.morph(cid, args); newCall->decl(newCall_decl); } } } } } else if (call->n_args()==2 && call->arg(0)->type().isintarray() && call->arg(1)->type().isint()) { GCLock lock; ASTString cid; switch (bot) { case BOT_EQ: cid = ASTString("count_eq"); break; case BOT_GQ: cid = ASTString("count_leq"); break; case BOT_GR: cid = ASTString("count_lt"); break; case BOT_LQ: cid = ASTString("count_geq"); break; case BOT_LE: cid = ASTString("count_gt"); break; case BOT_NQ: cid = ASTString("count_neq"); break; default: assert(false); } std::vector args({call->arg(0),call->arg(1),rhs}); FunctionI* newCall_decl = _model->matchFn(_env, cid, args, true); if (newCall_decl==nullptr) { throw InternalError("could not replace binary operator by call to "+cid.str()); } else { Call* newCall = bop.morph(cid, args); newCall->decl(newCall_decl); } } } } } else { throw TypeError(_env,bop.loc(), std::string("type error in operator application for `")+ bop.opToString().str()+"'. No matching operator found with left-hand side type `" +bop.lhs()->type().toString(_env)+ "' and right-hand side type `"+bop.rhs()->type().toString(_env)+"'"); } } /// Visit unary operator void vUnOp(UnOp& uop) { std::vector args(1); args[0] = uop.e(); if (FunctionI* fi = _model->matchFn(_env,uop.opToString(),args,true)) { uop.e(addCoercion(_env, _model,uop.e(),fi->argtype(_env,args,0))()); args[0] = uop.e(); Type ty = fi->rtype(_env,args,true); ty.cv(uop.e()->type().cv()); uop.type(ty); if (fi->e()) uop.decl(fi); } else { throw TypeError(_env,uop.loc(), std::string("type error in operator application for `")+ uop.opToString().str()+"'. No matching operator found with type `"+uop.e()->type().toString(_env)+"'"); } } static std::string createEnumToStringName(Id* ident, std::string prefix) { std::string name = ident->str().str(); if (name[0]=='\'') { name = "'"+prefix+name.substr(1); } else { name = prefix+name; } return name; } /// Visit call void vCall(Call& call) { std::vector args(call.n_args()); for (unsigned int i=static_cast(args.size()); i--;) args[i] = call.arg(i); if (FunctionI* fi = _model->matchFn(_env,call.id(),args,true)) { if (fi->e() && fi->e()->isa()) { Call* next_call = fi->e()->cast(); if (next_call->decl() && next_call->n_args()==fi->params().size() && _model->sameOverloading(_env, args, fi, next_call->decl())) { bool macro = true; for (unsigned int i=0; iparams().size(); i++) { if (!Expression::equal(next_call->arg(i),fi->params()[i]->id())) { macro = false; break; } } if (macro) { call.decl(next_call->decl()); for (ExpressionSetIter esi = next_call->ann().begin(); esi != next_call->ann().end(); ++esi) { call.addAnnotation(*esi); } call.rehash(); fi = next_call->decl(); } } } bool cv = false; for (unsigned int i=0; idyn_cast()) { Type t_before = c->e()->type(); Type t = fi->argtype(_env,args,i); t.dim(0); c->e(addCoercion(_env, _model, c->e(), t)()); Type t_after = c->e()->type(); if (t_before != t_after) { Type ct = c->type(); ct.bt(t_after.bt()); c->type(ct); } } else { args[i] = addCoercion(_env, _model,call.arg(i),fi->argtype(_env,args,i))(); call.arg(i, args[i]); } cv = cv || args[i]->type().cv(); } // Replace par enums with their string versions if (call.id()=="format" || call.id()=="show" || call.id()=="showDzn" || call.id()=="showJSON") { if (call.arg(call.n_args()-1)->type().ispar()) { int enumId = call.arg(call.n_args()-1)->type().enumId(); if (enumId != 0 && call.arg(call.n_args()-1)->type().dim() != 0) { const std::vector& enumIds = _env.getArrayEnum(enumId); enumId = enumIds[enumIds.size()-1]; } if (enumId > 0) { VarDecl* enumDecl = _env.getEnum(enumId)->e(); if (enumDecl->e()) { Id* ti_id = _env.getEnum(enumId)->e()->id(); GCLock lock; std::vector args(3); args[0] = call.arg(call.n_args()-1); if (args[0]->type().dim() > 1) { std::vector a1dargs(1); a1dargs[0] = args[0]; Call* array1d = new Call(Location().introduce(),ASTString("array1d"),a1dargs); Type array1dt = args[0]->type(); array1dt.dim(1); array1d->type(array1dt); args[0] = array1d; } args[1] = constants().boollit(call.id()=="showDzn"); args[2] = constants().boollit(call.id()=="showJSON"); ASTString enumName(createEnumToStringName(ti_id, "_toString_")); call.id(enumName); call.args(args); if (call.id()=="showDzn") { call.id(constants().ids.show); } fi = _model->matchFn(_env,&call,false); if (fi==NULL) { std::ostringstream oss; oss << "no function or predicate with this signature found: `"; oss << call.id() << "("; for (unsigned int i=0; itype().toString(_env); if (irtype(_env,args,true); ty.cv(cv); call.type(ty); if (Call* deprecated = fi->ann().getCall(constants().ann.mzn_deprecated)) { // rewrite this call into a call to mzn_deprecate(..., e) GCLock lock; std::vector params(call.n_args()); for (unsigned int i=0; itype(ty); origCall->decl(fi); call.id(constants().ids.mzn_deprecate); std::vector args({new StringLit(Location(), fi->id()), deprecated->arg(0), deprecated->arg(1), origCall}); call.args(args); FunctionI* deprecated_fi = _model->matchFn(_env, &call, false); if (deprecated_fi==NULL) { std::ostringstream oss; oss << "no function or predicate with this signature found: `"; oss << call.id() << "("; for (unsigned int i=0; itype().toString(_env); if (itype().toString(_env); if (itype().cv(); if (VarDecl* vdi = li->dyn_cast()) { if (vdi->e()==NULL && vdi->type().is_set() && vdi->type().isvar() && vdi->ti()->domain()==NULL) { _typeErrors.push_back(TypeError(_env,vdi->loc(), "set element type for `"+vdi->id()->str().str()+"' is not finite")); } if (vdi->type().ispar() && vdi->e() == NULL) throw TypeError(_env,vdi->loc(), "let variable `"+vdi->id()->v().str()+"' must be initialised"); if (vdi->ti()->hasTiVariable()) { _typeErrors.push_back(TypeError(_env,vdi->loc(), "type-inst variables not allowed in type-inst for let variable `"+vdi->id()->str().str()+"'")); } let.let_orig()[j++] = vdi->e(); for (unsigned int k=0; kti()->ranges().size(); k++) { let.let_orig()[j++] = vdi->ti()->ranges()[k]->domain(); } } isVar |= li->type().isvar(); } Type ty = let.in()->type(); ty.cv(cv); if (isVar && ty.bt()==Type::BT_BOOL && ty.dim()==0) ty.ti(Type::TI_VAR); let.type(ty); } /// Visit variable declaration void vVarDecl(VarDecl& vd) { if (ignoreVarDecl) { if (vd.e()) { Type vdt = vd.ti()->type(); Type vet = vd.e()->type(); if (vdt.enumId() != 0 && vdt.dim() > 0 && (vd.e()->isa() || vd.e()->isa() || (vd.e()->isa() && vd.e()->cast()->op()==BOT_PLUSPLUS))) { // Special case: index sets of array literals and comprehensions automatically // coerce to any enum index set const std::vector& enumIds = _env.getArrayEnum(vdt.enumId()); if (enumIds[enumIds.size()-1]==0) { vdt.enumId(0); } else { std::vector nEnumIds(enumIds.size()); for (unsigned int i=0; iisEnum() && vd.e()->isa()) { if (vd.e()->cast()->id()=="anon_enum") { vet.enumId(vdt.enumId()); } } if (vd.type().isunknown()) { vd.ti()->type(vet); vd.type(vet); } else if (! _env.isSubtype(vet,vdt,true)) { if (vet == Type::bot(1) && vd.e()->isa() && vd.e()->cast()->size()==0 && vdt.dim() != 0) { // this is okay: assigning an empty array (one-dimensional) to an array variable } else { _typeErrors.push_back(TypeError(_env,vd.e()->loc(), "initialisation value for `"+vd.id()->str().str()+"' has invalid type-inst: expected `"+ vd.ti()->type().toString(_env)+"', actual `"+vd.e()->type().toString(_env)+"'")); } } else { vd.e(addCoercion(_env, _model, vd.e(), vd.ti()->type())()); } } else { assert(!vd.type().isunknown()); } } else { vd.type(vd.ti()->type()); vd.id()->type(vd.type()); } } /// Visit type inst void vTypeInst(TypeInst& ti) { Type tt = ti.type(); bool foundEnum = ti.ranges().size()>0 && ti.domain() && ti.domain()->type().enumId() != 0; if (ti.ranges().size()>0) { bool foundTIId=false; for (unsigned int i=0; itype().cv()) tt.cv(true); if (ri->type().enumId() != 0) { foundEnum = true; } if (ri->type() == Type::top()) { // if (foundTIId) { // throw TypeError(_env,ri->loc(), // "only one type-inst variable allowed in array index"); // } else { foundTIId = true; // } } else if (ri->type() != Type::parint()) { assert(ri->isa()); TypeInst* riti = ri->cast(); if (riti->domain()) { throw TypeError(_env,ri->loc(), "array index set expression has invalid type, expected `set of int', actual `set of "+ ri->type().toString(_env)+"'"); } else { throw TypeError(_env,ri->loc(), "cannot use `"+ri->type().toString(_env)+"' as array index set (did you mean `int'?)"); } } } tt.dim(foundTIId ? -1 : ti.ranges().size()); } if (ti.domain() && ti.domain()->type().cv()) tt.cv(true); if (ti.domain()) { if (TIId* tiid = ti.domain()->dyn_cast()) { if (tiid->isEnum()) { tt.bt(Type::BT_INT); } } else { if (ti.domain()->type().ti() != Type::TI_PAR || ti.domain()->type().st() != Type::ST_SET) throw TypeError(_env,ti.domain()->loc(), "type-inst must be par set but is `"+ti.domain()->type().toString(_env)+"'"); if (ti.domain()->type().dim() != 0) throw TypeError(_env,ti.domain()->loc(), "type-inst cannot be an array"); } } if (tt.isunknown() && ti.domain()) { assert(ti.domain()); switch (ti.domain()->type().bt()) { case Type::BT_INT: case Type::BT_FLOAT: break; case Type::BT_BOT: { Type tidt = ti.domain()->type(); tidt.bt(Type::BT_INT); ti.domain()->type(tidt); } break; default: throw TypeError(_env,ti.domain()->loc(), "type-inst must be int or float"); } tt.bt(ti.domain()->type().bt()); tt.enumId(ti.domain()->type().enumId()); } else { // assert(ti.domain()==NULL || ti.domain()->isa()); } if (foundEnum) { std::vector enumIds(ti.ranges().size()+1); for (unsigned int i=0; itype().enumId(); } enumIds[ti.ranges().size()] = ti.domain() ? ti.domain()->type().enumId() : 0; int arrayEnumId = _env.registerArrayEnum(enumIds); tt.enumId(arrayEnumId); } if (tt.st()==Type::ST_SET && tt.ti()==Type::TI_VAR && tt.bt() != Type::BT_INT && tt.bt() != Type::BT_TOP) throw TypeError(_env,ti.loc(), "var set element types other than `int' not allowed"); ti.type(tt); } void vTIId(TIId& id) {} }; void typecheck(Env& env, Model* origModel, std::vector& typeErrors, bool ignoreUndefinedParameters, bool allowMultiAssignment, bool isFlatZinc) { Model* m; if (!isFlatZinc && origModel==env.model()) { // Combine all items into single model Model* combinedModel = new Model; class Combiner : public ItemVisitor { public: Model* m; Combiner(Model* m0) : m(m0) {} bool enter(Item* i) { if (!i->isa()) m->addItem(i); return true; } } _combiner(combinedModel); iterItems(_combiner, origModel); env.envi().orig_model = origModel; env.envi().model = combinedModel; m=combinedModel; } else { m = origModel; } // Topological sorting TopoSorter ts(m); std::vector functionItems; std::vector assignItems; Model* enumItems = new Model; class TSVFuns : public ItemVisitor { public: EnvI& env; Model* model; std::vector& fis; TSVFuns(EnvI& env0, Model* model0, std::vector& fis0) : env(env0), model(model0), fis(fis0) {} void vFunctionI(FunctionI* i) { model->registerFn(env, i); fis.push_back(i); } } _tsvf(env.envi(),m,functionItems); iterItems(_tsvf,m); class TSV0 : public ItemVisitor { public: EnvI& env; TopoSorter& ts; Model* model; bool hadSolveItem; std::vector& ais; VarDeclI* objective; Model* enumis; TSV0(EnvI& env0, TopoSorter& ts0, Model* model0, std::vector& ais0, Model* enumis0) : env(env0), ts(ts0), model(model0), hadSolveItem(false), ais(ais0), objective(NULL), enumis(enumis0) {} void vAssignI(AssignI* i) { ais.push_back(i); } void vVarDeclI(VarDeclI* i) { ts.add(env, i, true, enumis); // initialise new identifier counter to be larger than existing identifier if (i->e()->id()->idn() >= 0) { env.minId(i->e()->id()->idn()); } else if (i->e()->id()->v().beginsWith("X_INTRODUCED_") && i->e()->id()->v().endsWith("_")) { std::string numId = i->e()->id()->v().str().substr(std::string("X_INTRODUCED_").size()); if (numId.size() > 0) { numId = numId.substr(0,numId.size()-1); if (numId.size() > 0) { int vId = -1; try { vId = std::stoi(numId); } catch(std::exception&) {} if (vId >= 0) env.minId(vId); } } } } void vSolveI(SolveI* si) { if (hadSolveItem) throw TypeError(env,si->loc(),"Only one solve item allowed"); hadSolveItem = true; if (si->e()) { GCLock lock; TypeInst* ti = new TypeInst(Location().introduce(), Type()); VarDecl* obj = new VarDecl(Location().introduce(), ti, "_objective", si->e()); si->e(obj->id()); objective = new VarDeclI(Location().introduce(), obj); } } } _tsv0(env.envi(),ts,m,assignItems,enumItems); iterItems(_tsv0,m); if (_tsv0.objective) { m->addItem(_tsv0.objective); ts.add(env.envi(), _tsv0.objective, true, enumItems); } for (unsigned int i=0; isize(); i++) { if (AssignI* ai = (*enumItems)[i]->dyn_cast()) { assignItems.push_back(ai); } else if (VarDeclI* vdi = (*enumItems)[i]->dyn_cast()) { m->addItem(vdi); ts.add(env.envi(), vdi, false, enumItems); } else { FunctionI* fi = (*enumItems)[i]->dyn_cast(); m->addItem(fi); m->registerFn(env.envi(),fi); functionItems.push_back(fi); } } Model* enumItems2 = new Model; for (unsigned int i=0; iid(),ai->loc()); } catch (TypeError&) {} } else { vd = ts.get(env.envi(),ai->id(),ai->loc()); } if (vd) { if (vd->e()) { if (allowMultiAssignment) { GCLock lock; m->addItem(new ConstraintI(ai->loc(), new BinOp(ai->loc(), new Id(Location().introduce(),ai->id(),vd), BOT_EQ, ai->e()))); } else { throw TypeError(env.envi(),ai->loc(),"multiple assignment to the same variable"); } } else { vd->e(ai->e()); vd->ann().add(constants().ann.rhs_from_assignment); if (vd->ti()->isEnum()) { GCLock lock; ASTString name(createEnumToStringName(vd->id(),"_enum_to_string_")); VarDecl* vd_enum = ts.get(env.envi(),name,vd->loc()); if (vd_enum->e()) throw TypeError(env.envi(),ai->loc(),"multiple definition of the same enum"); AssignI* ai_enum = createEnumMapper(env.envi(), m, vd->ti()->type().enumId(), vd, vd_enum, enumItems2); if (ai_enum) { vd_enum->e(ai_enum->e()); ai_enum->remove(); } } } } ai->remove(); } for (unsigned int i=0; isize(); i++) { if (VarDeclI* vdi = (*enumItems2)[i]->dyn_cast()) { m->addItem(vdi); ts.add(env.envi(), vdi, false, enumItems); } else { FunctionI* fi = (*enumItems2)[i]->cast(); m->addItem(fi); m->registerFn(env.envi(),fi); functionItems.push_back(fi); } } delete enumItems; delete enumItems2; class TSV1 : public ItemVisitor { public: EnvI& env; TopoSorter& ts; TSV1(EnvI& env0, TopoSorter& ts0) : env(env0), ts(ts0) {} void vVarDeclI(VarDeclI* i) { ts.run(env,i->e()); } void vAssignI(AssignI* i) {} void vConstraintI(ConstraintI* i) { ts.run(env,i->e()); } void vSolveI(SolveI* i) { for (ExpressionSetIter it = i->ann().begin(); it != i->ann().end(); ++it) ts.run(env,*it); ts.run(env,i->e()); } void vOutputI(OutputI* i) { ts.run(env,i->e()); } void vFunctionI(FunctionI* fi) { ts.run(env,fi->ti()); for (unsigned int i=0; iparams().size(); i++) ts.run(env,fi->params()[i]); for (ExpressionSetIter it = fi->ann().begin(); it != fi->ann().end(); ++it) ts.run(env,*it); ts.scopes.push(false); for (unsigned int i=0; iparams().size(); i++) ts.scopes.add(env,fi->params()[i]); ts.run(env,fi->e()); ts.scopes.pop(); } } _tsv1(env.envi(),ts); iterItems(_tsv1,m); m->sortFn(); { struct SortByPayload { bool operator ()(Item* i0, Item* i1) { if (i0->isa()) return !i1->isa(); if (VarDeclI* vdi0 = i0->dyn_cast()) { if (VarDeclI* vdi1 = i1->dyn_cast()) { return vdi0->e()->payload() < vdi1->e()->payload(); } else { return !i1->isa(); } } return false; } } _sbp; std::stable_sort(m->begin(), m->end(), _sbp); } { Typer ty(env.envi(), m, typeErrors, ignoreUndefinedParameters); BottomUpIterator > bu_ty(ty); for (unsigned int i=0; ipayload(0); bu_ty.run(ts.decls[i]->ti()); ty.vVarDecl(*ts.decls[i]); } for (unsigned int i=0; iti()); for (unsigned int j=0; jparams().size(); j++) bu_ty.run(functionItems[i]->params()[j]); } } m->fixFnMap(); { Typer ty(env.envi(), m, typeErrors, ignoreUndefinedParameters); BottomUpIterator > bu_ty(ty); class TSV2 : public ItemVisitor { public: EnvI& env; Model* m; BottomUpIterator >& bu_ty; std::vector& _typeErrors; TSV2(EnvI& env0, Model* m0, BottomUpIterator >& b, std::vector& typeErrors) : env(env0), m(m0), bu_ty(b), _typeErrors(typeErrors) {} void vVarDeclI(VarDeclI* i) { bu_ty.run(i->e()); if (i->e()->ti()->hasTiVariable()) { _typeErrors.push_back(TypeError(env, i->e()->loc(), "type-inst variables not allowed in type-inst for `"+i->e()->id()->str().str()+"'")); } VarDecl* vdi = i->e(); if (vdi->e()==NULL && vdi->type().is_set() && vdi->type().isvar() && vdi->ti()->domain()==NULL) { _typeErrors.push_back(TypeError(env,vdi->loc(), "set element type for `"+vdi->id()->str().str()+"' is not finite")); } if (i->e()->ann().contains(constants().ann.output_only) && vdi->e()->type().isvar()) { _typeErrors.push_back(TypeError(env,vdi->loc(),"variables annotated with ::output_only must be par")); } } void vAssignI(AssignI* i) { bu_ty.run(i->e()); if (!env.isSubtype(i->e()->type(),i->decl()->ti()->type(),true)) { _typeErrors.push_back(TypeError(env, i->loc(), "assignment value for `"+i->decl()->id()->str().str()+"' has invalid type-inst: expected `"+ i->decl()->ti()->type().toString(env)+"', actual `"+i->e()->type().toString(env)+"'")); // Assign to "true" constant to avoid generating further errors that the parameter // is undefined i->decl()->e(constants().lit_true); } } void vConstraintI(ConstraintI* i) { bu_ty.run(i->e()); if (!env.isSubtype(i->e()->type(),Type::varbool(),true)) throw TypeError(env, i->loc(), "invalid type of constraint, expected `" +Type::varbool().toString(env)+"', actual `"+i->e()->type().toString(env)+"'"); } void vSolveI(SolveI* i) { for (ExpressionSetIter it = i->ann().begin(); it != i->ann().end(); ++it) { bu_ty.run(*it); if (!(*it)->type().isann()) throw TypeError(env, (*it)->loc(), "expected annotation, got `"+(*it)->type().toString(env)+"'"); } bu_ty.run(i->e()); if (i->e()) { Type et = i->e()->type(); bool needOptCoercion = et.isopt() && et.isint(); if (needOptCoercion) { et.ot(Type::OT_PRESENT); } if (! (env.isSubtype(et,Type::varint(),true) || env.isSubtype(et,Type::varfloat(),true))) throw TypeError(env, i->e()->loc(), "objective has invalid type, expected int or float, actual `"+et.toString(env)+"'"); if (needOptCoercion) { GCLock lock; std::vector args(2); args[0] = i->e(); args[1] = constants().boollit(i->st()==SolveI::ST_MAX); Call* c = new Call(Location().introduce(), ASTString("objective_deopt_"), args); c->decl(env.model->matchFn(env, c, false)); assert(c->decl()); c->type(et); i->e(c); } } } void vOutputI(OutputI* i) { bu_ty.run(i->e()); if (i->e()->type() != Type::parstring(1) && i->e()->type() != Type::bot(1)) throw TypeError(env, i->e()->loc(), "invalid type in output item, expected `" +Type::parstring(1).toString(env)+"', actual `"+i->e()->type().toString(env)+"'"); } void vFunctionI(FunctionI* i) { for (ExpressionSetIter it = i->ann().begin(); it != i->ann().end(); ++it) { bu_ty.run(*it); if (!(*it)->type().isann()) throw TypeError(env, (*it)->loc(), "expected annotation, got `"+(*it)->type().toString(env)+"'"); } bu_ty.run(i->ti()); bu_ty.run(i->e()); if (i->e() && !env.isSubtype(i->e()->type(),i->ti()->type(),true)) throw TypeError(env, i->e()->loc(), "return type of function does not match body, declared type is `" +i->ti()->type().toString(env)+ "', body type is `"+i->e()->type().toString(env)+"'"); if (i->e() && i->e()->type().ispar() && i->ti()->type().isvar()) { // this is a par function declared as var, so change declared return type Type i_t = i->ti()->type(); i_t.ti(Type::TI_PAR); i->ti()->type(i_t); } if (i->e()) i->e(addCoercion(env, m, i->e(), i->ti()->type())()); } } _tsv2(env.envi(), m, bu_ty, typeErrors); iterItems(_tsv2,m); } class TSV3 : public ItemVisitor { public: EnvI& env; Model* m; OutputI* outputItem; TSV3(EnvI& env0, Model* m0) : env(env0), m(m0), outputItem(NULL) {} void vAssignI(AssignI* i) { i->decl()->e(addCoercion(env, m, i->e(), i->decl()->type())()); } void vOutputI(OutputI* oi) { if (outputItem==NULL) { outputItem = oi; } else { GCLock lock; BinOp* bo = new BinOp(Location().introduce(),outputItem->e(),BOT_PLUSPLUS,oi->e()); bo->type(Type::parstring(1)); outputItem->e(bo); oi->remove(); m->setOutputItem(outputItem); } } } _tsv3(env.envi(),m); if (typeErrors.empty()) { iterItems(_tsv3,m); } try { m->checkFnOverloading(env.envi()); } catch (TypeError& e) { typeErrors.push_back(e); } for (unsigned int i=0; itoplevel() && ts.decls[i]->type().ispar() && !ts.decls[i]->type().isann() && ts.decls[i]->e()==NULL) { if (ts.decls[i]->type().isopt() && ts.decls[i]->type().dim()==0) { ts.decls[i]->e(constants().absent); } else if (!ignoreUndefinedParameters) { typeErrors.push_back(TypeError(env.envi(), ts.decls[i]->loc(), " symbol error: variable `" + ts.decls[i]->id()->str().str() + "' must be defined (did you forget to specify a data file?)")); } } if (ts.decls[i]->ti()->isEnum()) { ts.decls[i]->ti()->setIsEnum(false); Type vdt = ts.decls[i]->ti()->type(); vdt.enumId(0); ts.decls[i]->ti()->type(vdt); } } for (auto vd_k : env.envi().checkVars) { try { VarDecl* vd = ts.get(env.envi(), vd_k()->cast()->id()->str(), vd_k()->cast()->loc()); vd->ann().add(constants().ann.mzn_check_var); if (vd->type().enumId() != 0) { GCLock lock; int enumId = vd->type().enumId(); if (vd->type().dim() > 0) { const std::vector& arrayEnumIds = env.envi().getArrayEnum(vd->type().enumId()); enumId = arrayEnumIds[arrayEnumIds.size()-1]; } if (enumId > 0) { std::vector args({env.envi().getEnum(enumId)->e()->id()}); Call* checkEnum = new Call(Location().introduce(), constants().ann.mzn_check_enum_var, args); checkEnum->type(Type::ann()); checkEnum->decl(env.envi().model->matchFn(env.envi(), checkEnum, false)); vd->ann().add(checkEnum); } } Type vdktype = vd_k()->type(); vdktype.ti(Type::TI_VAR); if (!vd_k()->type().isSubtypeOf(vd->type(), false)) { GCLock lock; typeErrors.push_back(TypeError(env.envi(), vd->loc(), "Solution checker requires `"+vd->id()->str().str()+"' to be of type `"+ vdktype.toString(env.envi())+"'")); } } catch (TypeError& e) { typeErrors.push_back(TypeError(env.envi(), e.loc(), e.msg()+" (required by solution checker model)")); } } } void typecheck(Env& env, Model* m, AssignI* ai) { std::vector typeErrors; Typer ty(env.envi(), m, typeErrors, false); BottomUpIterator > bu_ty(ty); bu_ty.run(ai->e()); if (!typeErrors.empty()) { throw typeErrors[0]; } if (!env.envi().isSubtype(ai->e()->type(),ai->decl()->ti()->type(),true)) { throw TypeError(env.envi(), ai->e()->loc(), "assignment value for `"+ai->decl()->id()->str().str()+"' has invalid type-inst: expected `"+ ai->decl()->ti()->type().toString(env.envi())+"', actual `"+ai->e()->type().toString(env.envi())+"'"); } } void output_var_desc_json(Env& env, VarDecl* vd, std::ostream& os, bool extra = false) { os << " \"" << *vd->id() << "\" : {"; os << "\"type\" : "; switch (vd->type().bt()) { case Type::BT_INT: os << "\"int\""; break; case Type::BT_BOOL: os << "\"bool\""; break; case Type::BT_FLOAT: os << "\"float\""; break; case Type::BT_STRING: os << "\"string\""; break; case Type::BT_ANN: os << "\"ann\""; break; default: os << "\"?\""; break; } if (vd->type().ot()==Type::OT_OPTIONAL) { os << ", \"optional\" : true"; } if (vd->type().st()==Type::ST_SET) { os << ", \"set\" : true"; } if (vd->type().dim() > 0) { os << ", \"dim\" : " << vd->type().dim(); if(extra) { os << ", \"dims\" : ["; bool had_dim = false; ASTExprVec ranges = vd->ti()->ranges(); for(int i=0; i(ranges.size()); i++) { if(ranges[i]->type().enumId() > 0) { os << (had_dim ? "," : "") << "\"" << *env.envi().getEnum(ranges[i]->type().enumId())->e()->id() << "\""; } else { os << (had_dim ? "," : "") << "\"int\""; } had_dim = true; } os << "]"; if (vd->type().enumId() > 0) { const std::vector& enumIds = env.envi().getArrayEnum(vd->type().enumId()); if(enumIds.back() > 0) { os << ", \"enum_type\" : \"" << *env.envi().getEnum(enumIds.back())->e()->id() << "\""; } } } } else { if(extra) { if (vd->type().enumId() > 0) { os << ", \"enum_type\" : \"" << *env.envi().getEnum(vd->type().enumId())->e()->id() << "\""; } } } os << "}"; } void output_model_variable_types(Env& env, Model* m, std::ostream& os, const std::vector& skipDirs) { class VInfVisitor : public ItemVisitor { public: Env& env; const std::vector& skip_dirs; bool had_var; bool had_enum; std::ostringstream oss_vars; std::ostringstream oss_enums; VInfVisitor(Env& env0, const std::vector& skipDirs) : env(env0), skip_dirs(skipDirs), had_var(false), had_enum(false) {} bool enter(Item* i) { if (auto ii = i->dyn_cast()) { std::string prefix = ii->m()->filepath().str().substr(0,ii->m()->filepath().size()-ii->f().size()); for (const auto & skip_dir : skip_dirs) { if (prefix.substr(0, skip_dir.size()) == skip_dir) { return false; } } } return true; } void vVarDeclI(VarDeclI* vdi) { if (!vdi->e()->type().isann() && !vdi->e()->ti()->isEnum()) { if (had_var) oss_vars << ",\n"; output_var_desc_json(env, vdi->e(), oss_vars, true); had_var = true; } else if (vdi->e()->type().st()==Type::ST_SET && vdi->e()->type().enumId() != 0 && !vdi->e()->type().isann()) { if (had_enum) oss_enums << ", "; oss_enums << "\"" << *env.envi().getEnum(vdi->e()->type().enumId())->e()->id() << "\""; had_enum = true; } } } _vinf(env, skipDirs); iterItems(_vinf, m); os << "{\"var_types\": {"; os << "\n \"vars\": {\n" << _vinf.oss_vars.str() << "\n },"; os << "\n \"enums\": [" << _vinf.oss_enums.str() << "]\n"; os << "}}\n"; } void output_model_interface(Env& env, Model* m, std::ostream& os, const std::vector& skipDirs) { class IfcVisitor : public ItemVisitor { public: Env& env; const std::vector skip_dirs; bool had_input; bool had_output; bool had_add_to_output = false; std::ostringstream oss_input; std::ostringstream oss_output; std::string method; bool output_item; IfcVisitor(Env& env0, const std::vector& skipDirs) : env(env0), skip_dirs(skipDirs), had_input(false), had_output(false), method("sat"), output_item(false) {} bool enter(Item* i) { if (auto ii = i->dyn_cast()) { std::string prefix = ii->m()->filepath().str().substr(0,ii->m()->filepath().size()-ii->f().size()); for (const auto & skip_dir : skip_dirs) { if (prefix.substr(0, skip_dir.size()) == skip_dir) { return false; } } } return true; } void vVarDeclI(VarDeclI* vdi) { VarDecl* vd = vdi->e(); if (vd->type().ispar() && !vd->type().isann() && (vd->e()==NULL || vd->e()==constants().absent)) { if (had_input) oss_input << ",\n"; output_var_desc_json(env, vd, oss_input); had_input = true; } else { bool process_var = false; if (vd->ann().contains(constants().ann.add_to_output)) { if (!had_add_to_output) { oss_output.str(""); had_output = false; } had_add_to_output = true; process_var = true; } else if (!had_add_to_output) { process_var = vd->type().isvar() && (vd->e()==NULL || vd->ann().contains(constants().ann.rhs_from_assignment)); } if (process_var) { if (had_output) { oss_output << ",\n"; } output_var_desc_json(env, vd, oss_output); had_output = true; } } } void vSolveI(SolveI* si) { switch (si->st()) { case SolveI::ST_MIN: method = "min"; break; case SolveI::ST_MAX: method = "max"; break; case SolveI::ST_SAT: method = "sat"; break; } } void vOutputI(OutputI* oi) { output_item = true; } } _ifc(env, skipDirs); iterItems(_ifc, m); os << "{\n \"input\" : {\n" << _ifc.oss_input.str() << "\n },\n \"output\" : {\n" << _ifc.oss_output.str() << "\n }"; os << ",\n \"method\": \""; os << _ifc.method; os << "\""; os << ",\n \"has_output_item\": " << (_ifc.output_item ? "true" : "false"); os << "\n}\n"; } } libminizinc-2.4.2/lib/utils_savestream.cpp000066400000000000000000000021741360574160400207040ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was ! distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #include #else #include #endif #include #include using namespace std; using namespace MiniZinc; //StreamRedir::StreamRedir(FILE *s0) : d_s0(s0) { } StreamRedir::StreamRedir(FILE *s0, FILE *s1, bool fFlush) : d_s0(s0) { replaceStream(s1, fFlush); } StreamRedir::~StreamRedir() { restore(); } void StreamRedir::replaceStream(FILE *s1, bool fFlush) { if (fFlush) fflush(d_s0); fgetpos(d_s0, &(d_si.pos)); d_si.fd = dup(fileno(d_s0)); dup2(fileno(s1), fileno(d_s0)); } void StreamRedir::restore(bool fFLush) { if (fFLush) fflush(d_s0); dup2(d_si.fd, fileno(d_s0)); close(d_si.fd); clearerr(d_s0); fsetpos(d_s0, &(d_si.pos)); } libminizinc-2.4.2/lib/values.cpp000066400000000000000000000017441360574160400166130ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include namespace MiniZinc { const IntVal IntVal::minint(void) { return IntVal(std::numeric_limits::min()); } const IntVal IntVal::maxint(void) { return IntVal(std::numeric_limits::max()); } const IntVal IntVal::infinity(void) { return IntVal(1,true); } IntSetVal::IntSetVal(IntVal m, IntVal n) : ASTChunk(sizeof(Range)) { get(0).min = m; get(0).max = n; } FloatSetVal::FloatSetVal(FloatVal m, FloatVal n) : ASTChunk(sizeof(Range)) { get(0).min = m; get(0).max = n; } const FloatVal FloatVal::infinity(void) { return FloatVal(1.0,true); } } libminizinc-2.4.2/minizinc.cpp000066400000000000000000000045311360574160400163630ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* This (main) file coordinates flattening and solving. * The corresponding modules are flexibly plugged in * as derived classes, prospectively from DLLs. * A flattening module should provide MinZinc::GetFlattener() * A solving module should provide an object of a class derived from SolverFactory. * Need to get more flexible for multi-pass & multi-solving stuff TODO */ #include #include #include #include #include #include #include #include using namespace std; using namespace MiniZinc; int main(int argc, const char** argv) { Timer starttime; bool fSuccess = false; try { MznSolver slv(std::cout,std::cerr); try { std::vector args(argc-1); for (int i=1; i */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #include #include #include #include #include #include #include #include using namespace MiniZinc; using namespace std; bool beginswith(string s, string t) { return s.compare(0, t.length(), t)==0; } int main(int argc, char** argv) { string filename; vector includePaths; bool flag_ignoreStdlib = false; bool flag_verbose = false; bool flag_include_stdlib = false; bool flag_index = true; bool flag_rst = false; int toplevel_groups = 0; string output_base; string header_file; string footer_file; string std_lib_dir; if (char* MZNSTDLIBDIR = getenv("MZN_STDLIB_DIR")) { std_lib_dir = string(MZNSTDLIBDIR); } string globals_dir; if (argc < 2) goto error; for (int i=1; i 2) { includePaths.push_back(include.substr(2)+string("/")); } else { i++; if (i==argc) { goto error; } includePaths.push_back(argv[i]+string("/")); } } else if (string(argv[i])==string("--ignore-stdlib")) { flag_ignoreStdlib = true; } else if (string(argv[i])==string("-v") || string(argv[i])==string("--verbose")) { flag_verbose = true; } else if (string(argv[i])=="--stdlib-dir") { i++; if (i==argc) goto error; std_lib_dir = argv[i]; } else if (beginswith(string(argv[i]),"-G")) { string filename(argv[i]); if (filename.length() > 2) { globals_dir = filename.substr(2); } else { i++; if (i==argc) { goto error; } globals_dir = argv[i]; } } else if (string(argv[i])=="--toplevel-groups") { i++; if (i==argc) goto error; toplevel_groups = atoi(argv[i]); } else if (string(argv[i])=="--html-header" || string(argv[i])=="--rst-header") { i++; if (i==argc) goto error; header_file = string(argv[i]); } else if (string(argv[i])=="--html-footer" || string(argv[i])=="--rst-footer") { i++; if (i==argc) goto error; footer_file = string(argv[i]); } else if (string(argv[i])=="--include-stdlib") { flag_include_stdlib = true; } else if (string(argv[i])=="--no-index") { flag_index = false; } else if (string(argv[i])=="--globals-dir" || string(argv[i])=="--mzn-globals-dir") { i++; if (i==argc) goto error; globals_dir = argv[i]; } else if (string(argv[i])=="--output-base") { i++; if (i==argc) goto error; output_base = argv[i]; } else if (string(argv[i])=="--rst-output") { flag_rst = true; toplevel_groups = 0; } else { std::string input_file(argv[i]); if (input_file.length()<=4) { std::cerr << "Error: cannot handle file " << input_file << "." << std::endl; goto error; } size_t last_dot = input_file.find_last_of('.'); std::string extension; if (last_dot != string::npos) extension = input_file.substr(last_dot,string::npos); if (extension == ".mzn") { if (filename=="") { filename = input_file; } else { std::cerr << "Error: Multiple .mzn files given." << std::endl; goto error; } } else if (extension == ".dzn" || extension == ".json") { std::cerr << "Error: cannot generate documentation for data files." << std::endl; } else { std::cerr << "Error: cannot handle file extension " << extension << "." << std::endl; goto error; } } } if (filename=="") { std::cerr << "Error: no model file given." << std::endl; goto error; } if (std_lib_dir.empty()) { SolverConfigs solver_configs(std::cerr); std_lib_dir = solver_configs.mznlibDir(); } if (std_lib_dir.empty()) { std::cerr << "Error: unknown minizinc standard library directory.\n" << "Specify --stdlib-dir on the command line or set the\n" << "MZN_STDLIB_DIR environment variable.\n"; std::exit(EXIT_FAILURE); } if (globals_dir!="") { includePaths.push_back(std_lib_dir+"/"+globals_dir+"/"); } includePaths.push_back(std_lib_dir+"/std/"); for (unsigned int i=0; i(hs)), std::istreambuf_iterator()); header = str; header_title = str.find("@TITLE"); } string footer; if (!footer_file.empty()) { std::ifstream hs(footer_file); if (!hs.good()) { std::cerr << "Cannot open footer file " << footer_file << "\n"; std::exit(EXIT_FAILURE); } std::string str((std::istreambuf_iterator(hs)), std::istreambuf_iterator()); footer = str; } std::stringstream errstream; if (flag_verbose) std::cerr << "Parsing '" << filename << "'" << std::endl; std::vector filenames; filenames.push_back(filename); Env env; if (Model* m = parse(env, filenames, vector(), "", "", includePaths, flag_ignoreStdlib, true, flag_verbose, errstream)) { try { env.model(m); if (flag_verbose) std::cerr << "Done parsing." << std::endl; if (flag_verbose) std::cerr << "Typechecking ..."; vector typeErrors; MiniZinc::typecheck(env, m, typeErrors, true, false); if (typeErrors.size() > 0) { for (unsigned int i=0; i docs; if (flag_rst) { docs = RSTPrinter::printRST(env.envi(),m,basename,toplevel_groups,flag_include_stdlib,flag_index); } else { docs = HtmlPrinter::printHtml(env.envi(),m,basename,toplevel_groups,flag_include_stdlib,flag_index); } for (unsigned int i=0; i(errstream),istreambuf_iterator(),ostreambuf_iterator(std::cerr)); exit(EXIT_FAILURE); } } if (flag_verbose) std::cerr << "Done." << std::endl; return 0; error: std::string executable_name(argv[0]); executable_name = executable_name.substr(executable_name.find_last_of("/\\") + 1); std::cerr << "Usage: "<< executable_name << " [] [-I ] .mzn [.dzn ...]" << std::endl << std::endl << "Options:" << std::endl << " --help, -h\n Print this help message" << std::endl << " --version\n Print version information" << std::endl << " --ignore-stdlib\n Ignore the standard libraries stdlib.mzn and builtins.mzn" << std::endl << " -v, --verbose\n Print progress statements" << std::endl << " --stdlib-dir \n Path to MiniZinc standard library directory" << std::endl << " -G --globals-dir --mzn-globals-dir\n Search for included files in /." << std::endl << " --single-page\n Print entire documentation on a single HTML page." << std::endl << " --no-index\n Do not generate an index of all symbols." << std::endl << " --rst-output\n Generate ReStructuredText rather than HTML." << std::endl << " --html-header, --html-footer, --rst-header, --rst-footer\n Header/footer files to include in output." << std::endl << std::endl << "Output options:" << std::endl << std::endl << " --output-base \n Base name for output files" << std::endl ; exit(EXIT_FAILURE); } libminizinc-2.4.2/share/000077500000000000000000000000001360574160400151365ustar00rootroot00000000000000libminizinc-2.4.2/share/minizinc/000077500000000000000000000000001360574160400167565ustar00rootroot00000000000000libminizinc-2.4.2/share/minizinc/g12_fd/000077500000000000000000000000001360574160400200205ustar00rootroot00000000000000libminizinc-2.4.2/share/minizinc/g12_fd/all_different_int.mzn000066400000000000000000000017371360574160400242260ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Constrains the array of objects 'x' to be all different. %-----------------------------------------------------------------------------% predicate all_different_int(array[int] of var int: x) = g12fd_int_all_different(x); %-----------------------------------------------------------------------------% % The implementation of the all_different constraint in the G12/FD solver. % This should not be called directly, instead the definition above should % be used. predicate g12fd_int_all_different(array[int] of var int: x); % G12/FD doesn't provide a reified all_different so we use the following % definition if g12fd_int_all_different is called from a reified context. % predicate g12fd_int_all_different_reif(array[int] of var int: x, var bool: r) = r <-> forall(i,j in index_set(x) where i < j) ( x[i] != x[j] ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/g12_fd/cumulative.mzn000066400000000000000000000031621360574160400227260ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that a set of tasks given by start times 's', durations 'd', and % resource requirements 'r', never require more than a global resource bound % 'b' at any one time. % Assumptions: % - forall i, d[i] >= 0 and r[i] >= 0 %-----------------------------------------------------------------------------% predicate cumulative(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = assert(index_set(s) == index_set(d) /\ index_set(s) == index_set(r), "cumulative: the 3 array arguments must have identical index sets", assert(lb_array(d) >= 0 /\ lb_array(r) >= 0, "cumulative: durations and resource usages must be non-negative", g12fd_cumulative(s, d, r, b))); %-----------------------------------------------------------------------------% % Optional parameters that can be used with the built-in G12/FD cumulative % constraint. % annotation energy_feasibility_check; annotation edge_finding_filtering; annotation ext_edge_finding_filtering; annotation histogram_filtering; annotation idempotent; %-----------------------------------------------------------------------------% % The implementation of the cumulative constraint in the G12/FD solver. % This should not be called directly, instead the definition above should % be used. predicate g12fd_cumulative(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/g12_fd/global_cardinality_low_up.mzn000066400000000000000000000023111360574160400257530ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that for all 'i', the value 'cover[i]' appears at least 'lbound[i]' % and at most 'ubound[i]' times in the array 'x'. %-----------------------------------------------------------------------------% predicate global_cardinality_low_up(array[int] of var int: x, array[int] of int: cover, array[int] of int: lbound, array[int] of int: ubound) = g12fd_global_cardinality_open(x, cover, lbound, ubound); %-----------------------------------------------------------------------------% % The implementation in the G12/FD solver. This should not be called directly; % instead the definition above should be used. predicate g12fd_global_cardinality_open(array[int] of var int: x, array[int] of int: cover, array[int] of int: lbound, array[int] of int: ubound); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/g12_lazyfd/000077500000000000000000000000001360574160400207205ustar00rootroot00000000000000libminizinc-2.4.2/share/minizinc/g12_lazyfd/all_different_int.mzn000066400000000000000000000017561360574160400251270ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Constrains the array of objects 'x' to be all different. %-----------------------------------------------------------------------------% predicate all_different_int(array[int] of var int: x) = g12lazy_int_all_different(x); %-----------------------------------------------------------------------------% % The implementation of the all_different constraint in the G12/LazyFD solver. % This should not be called directly, instead the definition above should % be used. predicate g12lazy_int_all_different(array[int] of var int: x); % G12/LazyFD doesn't provide a reified all_different so we use the following % definition if g12lazy_int_all_different is called from a reified context. % predicate g12lazy_int_all_different_reif(array[int] of var int: x, var bool: r) = r <-> forall(i,j in index_set(x) where i < j) ( x[i] != x[j] ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/g12_lazyfd/redefinitions.mzn000066400000000000000000000033441360574160400243140ustar00rootroot00000000000000% FlatZinc built-in redefinitions for G12/LazyFD. predicate array_bool_element(var int : idx, array[int] of bool : arr, var bool : v) = let { int : N = length(arr), array[1..N] of var bool : tmp = [idx = I | I in 1..N] } in exists(I in 1..N)(tmp[I]) /\ forall(I in 1..N) (tmp[I] -> v = arr[I]); predicate array_var_bool_element(var int : idx, array[int] of var bool : arr, var bool : v) = let { int : N = length(arr), array[1..N] of var bool : tmp = [idx = I | I in 1..N] } in exists(I in 1..N)(tmp[I]) /\ forall(I in 1..N) (tmp[I] -> v = arr[I]); predicate array_bool_xor(array[int] of var bool: bs) = let { int: bs_lower = min(index_set(bs)), int: bs_upper = max(index_set(bs)), int: n = length(bs) } in if n == 1 then bs[bs_lower] else if n == 2 then bs[bs_lower] xor bs[bs_upper] else if n == 3 then bs[bs_lower] = (bs[bs_lower + 1] = bs[bs_upper]) else let { int: cs_lower = bs_lower + 1, int: cs_upper = bs_upper - 1, array [cs_lower..cs_upper] of var bool: cs } in forall(i in cs_lower..cs_upper-1)( cs[i+1] = bs[i+1] xor cs[i] ) /\ (cs[cs_lower] = bs[bs_lower] xor bs[bs_lower + 1]) /\ (bs[bs_upper] xor cs[cs_upper]) endif endif endif; predicate int_abs(var int: a, var int: b) = b >= 0 /\ b >= a /\ b >= -a /\ (b <= a \/ b <= - a); predicate int_mod(var int: a, var int: b, var int: c) = let { int : bnd = max([lb(a), ub(a), -lb(a), -ub(a)]), var -bnd .. bnd : z } in ( b >= 0 -> c >= 0 /\ c < b) /\ ( b <= 0 -> c <= 0 /\ c > b) /\ b * z + c = a; libminizinc-2.4.2/share/minizinc/geas/000077500000000000000000000000001360574160400176755ustar00rootroot00000000000000libminizinc-2.4.2/share/minizinc/geas/fzn_all_different_int.mzn000066400000000000000000000002251360574160400247470ustar00rootroot00000000000000predicate fzn_all_different_int(array [int] of var int: x) = geas_all_different_int(x); predicate geas_all_different_int(array [int] of var int: x); libminizinc-2.4.2/share/minizinc/geas/fzn_alldifferent_except_0.mzn000066400000000000000000000002431360574160400255250ustar00rootroot00000000000000predicate fzn_alldifferent_except_0(array [int] of var int: x) = geas_all_different_except_0(x); predicate geas_all_different_except_0(array [int] of var int: x); libminizinc-2.4.2/share/minizinc/geas/fzn_cumulative.mzn000066400000000000000000000011571360574160400234620ustar00rootroot00000000000000predicate geas_cumulative_var(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b); predicate geas_cumulative(array[int] of var int: s, array[int] of int: d, array[int] of int: r, int: b); predicate fzn_cumulative(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = geas_cumulative_var(s, d, r, b); %% TODO: once disjunctive propagator is fixed, add %% special case for b = 1. predicate fzn_cumulative(array[int] of var int: s, array[int] of int: d, array[int] of int: r, int: b) = geas_cumulative(s, d, r, b); libminizinc-2.4.2/share/minizinc/geas/fzn_disjunctive.mzn000066400000000000000000000005711360574160400236320ustar00rootroot00000000000000%predicate geas_disjunctive_var(array[int] of var int: s, % array[int] of var int: d); predicate geas_disjunctive(array[int] of var int: s, array[int] of int: d); %predicate disjunctive(array[int] of var int: s, array[int] of var int: d) = % geas_disjunctive_var(s, d); predicate fzn_disjunctive(array[int] of var int: s, array[int] of int: d) = geas_disjunctive(s, d); libminizinc-2.4.2/share/minizinc/geas/fzn_global_cardinality.mzn000066400000000000000000000012701360574160400251230ustar00rootroot00000000000000predicate fzn_global_cardinality(array[int] of var int: x, array[int] of int: cover, array[int] of int: count) = geas_global_cardinality(x, cover, count); predicate fzn_global_cardinality(array[int] of var int: x, array[int] of int: cover, array[int] of var int: count) = forall (i in index_set(cover)) ( count[i] = sum (j in index_set(x)) (bool2int(x[j] = cover[i])) ); predicate geas_global_cardinality(array[int] of var int: x, array[int] of int: cover, array[int] of int: count); libminizinc-2.4.2/share/minizinc/geas/fzn_inverse.mzn000066400000000000000000000003351360574160400227540ustar00rootroot00000000000000include "all_different.mzn"; predicate fzn_inverse(array [int] of var int: x, array [int] of var int: y) = alldifferent(x) /\ alldifferent(y) /\ forall (i in index_set(x), j in index_set(y)) (x[i] = j <-> y[j] = i); libminizinc-2.4.2/share/minizinc/geas/fzn_table_int.mzn000066400000000000000000000006211360574160400232400ustar00rootroot00000000000000predicate geas_table_int(array [int] of var int: x, array [int] of int: t); predicate fzn_table_int(array [int] of var int: x, array [int, int] of int: t) = assert (index_set_2of2(t) == index_set(x), "The second dimension of the table must equal the number of variables " ++ "in the first argument", geas_table_int(x, [ t[i,j] | i in index_set_1of2(t), j in index_set_2of2(t) ]) ); libminizinc-2.4.2/share/minizinc/geas/fzn_value_precede_int.mzn000066400000000000000000000004521360574160400247560ustar00rootroot00000000000000predicate fzn_value_precede_int(int: s, int: t, array[int] of var int: x) = let { var index_set(x): pos_s; constraint forall (i in index_set(x)) ( (pos_s <= i) -> (x[i] = s) \/ (pos_s < i) ); } in forall(i in index_set(x)) ( (x[i] = t) -> (pos_s < i) ); libminizinc-2.4.2/share/minizinc/geas/redefinitions-2.0.mzn000066400000000000000000000020621360574160400235620ustar00rootroot00000000000000% This file contains redefinitions of standard builtins that can be overridden % by solvers. predicate bool_clause_reif(array[int] of var bool: as, array[int] of var bool: bs, var bool: b) = clause(as,bs++[b]) /\ forall (i in index_set(as)) (as[i] -> b) /\ forall (i in index_set(bs)) (bs[i] \/ b); predicate array_float_maximum(var float: m, array[int] of var float: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), float: ly = lb_array(x), float: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == max(x[i],y[i-1]) ); predicate array_float_minimum(var float: m, array[int] of var float: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), float: ly = lb_array(x), float: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == min(x[i],y[i-1]) ); libminizinc-2.4.2/share/minizinc/geas/redefinitions.mzn000066400000000000000000000063721360574160400232750ustar00rootroot00000000000000%% New annotations annotation assume(array[int] of var bool: b); annotation int_priority(array[int] of var int: xs, array[int] of ann: br, ann: sel); annotation bool_priority(array[int] of var bool: xs, array[int] of ann: br, ann: sel); %% Half Reifications predicate int_eq_imp(var int: a, var int: b, var bool: r); predicate int_ne_imp(var int: a, var int: b, var bool: r); predicate int_le_imp(var int: a, var int: b, var bool: r); predicate int_lt_imp(var int: a, var int: b, var bool: r); predicate int_lin_eq_imp(array [int] of int: as, array [int] of var int: bs, int: c, var bool: r); predicate int_lin_ne_imp(array [int] of int: as, array [int] of var int: bs, int: c, var bool: r); predicate int_lin_le_imp(array [int] of int: as, array [int] of var int: bs, int: c, var bool: r); predicate bool_eq_imp(var bool: a, var bool: b, var bool: r); predicate bool_ne_imp(var bool: a, var bool: b, var bool: r); predicate bool_le_imp(var bool: a, var bool: b, var bool: r); predicate bool_lt_imp(var bool: a, var bool: b, var bool: r); predicate bool_or_imp(var bool: a, var bool: b, var bool: r); predicate bool_and_imp(var bool: a, var bool: b, var bool: r); predicate bool_xor_imp(var bool: a, var bool: b, var bool: r); predicate bool_clause_imp(array [int] of var bool: as, array [int] of var bool: bs, var bool: b); predicate array_bool_or_imp(array [int] of var bool: as, var bool: r); predicate array_bool_and_imp(array [int] of var bool: as, var bool: r); predicate bool_lin_eq_imp(array [int] of int: as, array [int] of var bool: bs, var int: c, var bool: r); predicate bool_lin_le_imp(array [int] of int: as, array [int] of var bool: bs, var int: c, var bool: r); predicate bool_lin_lt_imp(array [int] of int: as, array [int] of var bool: bs, var int: c, var bool: r); predicate bool_lin_ne_imp(array [int] of int: as, array [int] of var bool: bs, var int: c, var bool: r); %% Special cases for binary-ish x, y. predicate int_lin_eq_reif( array [int] of int: cs, array [int] of var int: xs, int: k, var bool: r) = let { var bool: a; var bool: b } in (r <-> (a /\ b)) /\ int_lin_le_reif(cs, xs, k, a) /\ int_lin_le_reif([-c | c in cs], xs, -k, b); predicate bool_xor(var bool: x, var bool: y, var bool: r) = bool_clause([x,y],[r]) /\ bool_clause([],[x,y,r]) /\ bool_clause([x, r], [y]) /\ bool_clause([y, r], [x]); predicate set_in_reif(var int: x, set of int: s, var bool: r) = if card(s) = max(s) - min(s) + 1 then r <-> (x >= min(s) /\ x <= max(s)) else bool_clause([x = k | k in s], [r]) /\ forall (k in s) (x = k -> r) endif; predicate int_pow(var int: x, var int: y, var int: z) = let { array [dom(x), dom(y)] of int: A = array2d( dom(x), dom(y), [ pow(a, b) | a in dom(x), b in dom(y) ] ); } in z = A[x, y]; predicate int_pow(var int: x, int: y, var int: z) = if y = 0 then z = 1 elseif y = 1 then z = x else let { var int: zp ::is_defined_var ; constraint int_pow(x, y div 2, zp) :: defines_var(zp); } in if y mod 2 = 0 then z = zp * zp else z = x * zp * zp endif endif; libminizinc-2.4.2/share/minizinc/gecode_presolver/000077500000000000000000000000001360574160400223055ustar00rootroot00000000000000libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_all_different_int.mzn000066400000000000000000000036301360574160400273620ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2009-09-09 01:42:03 +1000 (Wed, 09 Sep 2009) $ by $Author: schulte $ % $Revision: 9689 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_all_different_int(array[int] of var int: x); %predicate all_different_int(array[int] of var int: x) = gecode_all_different_int(x); predicate fzn_all_different_int(array[int] of var int: xs) = let { set of int: cs = {fix(x) | x in xs where is_fixed(x)}; array[int] of var int: ys = [x | x in xs where not is_fixed(x)]; constraint forall(y in ys, c in cs) (y != c); } in if length(ys) <= 1 then true elseif length(ys) == 2 then ys[1] != ys[2] else gecode_all_different_int(ys) endif; libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_all_equal_int.mzn000066400000000000000000000026711360574160400265270ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2010-03-31 19:18:34 +1100 (Wed, 31 Mar 2010) $ by $Author: tack $ % $Revision: 10618 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_all_equal_int(array[int] of var int: x); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_among.mzn000066400000000000000000000027141360574160400250150ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2011-08-22 05:22:06 +1000 (Mon, 22 Aug 2011) $ by $Author: tack $ % $Revision: 12325 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_among(var int: n, array[int] of var int: x, set of int: v); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_arg_max_int.mzn000066400000000000000000000003121360574160400261740ustar00rootroot00000000000000predicate gecode_maximum_arg_int(array[int] of var int: x, var int: i); predicate fzn_maximum_arg_int(array[int] of var int: x, var int: i) = gecode_maximum_arg_int(x,(i-min(index_set(x)))::domain); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_arg_min_int.mzn000066400000000000000000000003121360574160400261720ustar00rootroot00000000000000predicate gecode_minimum_arg_int(array[int] of var int: x, var int: i); predicate fzn_minimum_arg_int(array[int] of var int: x, var int: i) = gecode_minimum_arg_int(x,(i-min(index_set(x)))::domain); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_at_least_int.mzn000066400000000000000000000027121360574160400263600ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2009-09-09 01:42:03 +1000 (Wed, 09 Sep 2009) $ by $Author: schulte $ % $Revision: 9689 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_at_least_int(int: n, array[int] of var int: x, int: v); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_at_least_set.mzn000066400000000000000000000030161360574160400263570ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2009-09-09 01:42:03 +1000 (Wed, 09 Sep 2009) $ by $Author: schulte $ % $Revision: 9689 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_at_least_set(int: n, array[int] of var set of int: x, set of int: v) = bool_sum_ge([x[i] == v | i in index_set(x)], n); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_at_most_int.mzn000066400000000000000000000027111360574160400262310ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2009-09-09 01:42:03 +1000 (Wed, 09 Sep 2009) $ by $Author: schulte $ % $Revision: 9689 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_at_most_int(int: n, array[int] of var int: x, int: v); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_at_most_set.mzn000066400000000000000000000030151360574160400262300ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2009-09-09 01:42:03 +1000 (Wed, 09 Sep 2009) $ by $Author: schulte $ % $Revision: 9689 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_at_most_set(int: n, array[int] of var set of int: x, set of int: v) = bool_sum_le([x[i] == v | i in index_set(x)], n); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_bin_packing.mzn000066400000000000000000000033171360574160400261600ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2010 % % Last modified: % $Date: 2013-07-19 10:50:31 +1000 (Fri, 19 Jul 2013) $ by $Author: tack $ % $Revision: 13902 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % include "bin_packing_capa.mzn"; predicate fzn_bin_packing(int: c, array[int] of var int: bin, array[int] of int: w) = let { set of int: idx = lb_array(bin)..ub_array(bin), array[idx] of int: capa = array1d(idx, [c|i in idx]) } in bin_packing_capa(capa,bin,w); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_bin_packing_capa.mzn000066400000000000000000000034021360574160400271370ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2010 % % Last modified: % $Date: 2013-07-19 10:50:31 +1000 (Fri, 19 Jul 2013) $ by $Author: tack $ % $Revision: 13902 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % include "bin_packing_load.mzn"; predicate fzn_bin_packing_capa(array[int] of int: c, array[int] of var int: bin, array[int] of int: w) = let { array[min(index_set(c))..max(index_set(c))] of var 0..ub_array(c): l } in ( forall( i in index_set(l) ) ( l[i] <= c[i] ) /\ bin_packing_load(l,bin,w) ); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_bin_packing_load.mzn000066400000000000000000000035021360574160400271530ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2010 % % Last modified: % $Date: 2012-03-19 11:56:37 +1100 (Mon, 19 Mar 2012) $ by $Author: tack $ % $Revision: 12583 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_bin_packing_load(array[int] of var int: l, array[int] of var int: bin, array[int] of int: w, int: minIndex); predicate fzn_bin_packing_load(array[int] of var int: l, array[int] of var int: bin, array[int] of int: w) = gecode_bin_packing_load(l,bin,w,min(index_set(l))); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_circuit.mzn000066400000000000000000000032221360574160400253510ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2012-10-22 09:04:10 +1100 (Mon, 22 Oct 2012) $ by $Author: tack $ % $Revision: 13159 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_circuit(int: offset, array[int] of var int: x); predicate fzn_circuit(array[int] of var int: x) = if min(index_set(x)) >= 0 then gecode_circuit(min(index_set(x)),x) else gecode_circuit(0,[x[i]-min(index_set(x)) | i in index_set(x)]) endif; libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_count_eq.mzn000066400000000000000000000030611360574160400255250ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2012-08-14 10:15:14 +1000 (Tue, 14 Aug 2012) $ by $Author: tack $ % $Revision: 12979 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_count(array[int] of var int: x, var int: y, var int: c); predicate fzn_count_eq(array[int] of var int: x, var int: y, var int: c) = gecode_count(x, y, c); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_count_eq_reif.mzn000066400000000000000000000032251360574160400265340ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2012-08-14 10:15:14 +1000 (Tue, 14 Aug 2012) $ by $Author: tack $ % $Revision: 12979 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_count_reif(array[int] of var int: x, var int: y, var int: c, var bool: b); predicate fzn_count_eq_reif(array[int] of var int: x, var int: y, var int: c, var bool: b) = gecode_count_reif(x, y, c, b); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_cumulative.mzn000066400000000000000000000042471360574160400260750ustar00rootroot00000000000000% % Main authors: % Guido Tack % Mikael lagerkvist % % Copyright: % Guido Tack, 2007 % Mikael Lagerkvist, 2009 % % Last modified: % $Date: 2011-03-08 19:54:48 +1100 (Tue, 08 Mar 2011) $ by $Author: tack $ % $Revision: 11787 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_cumulative(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = assert(index_set(s) == index_set(d) /\ index_set(s) == index_set(r), "cumulative: the 3 array arguments must have identical index sets", assert(lb_array(d) >= 0 /\ lb_array(r) >= 0, "cumulative: durations and resource usages must be non-negative", cumulatives(s, d, r, b) ) ); % Specialized cumulatives propagator is only for fixed bounds predicate cumulatives(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_decreasing_bool.mzn000066400000000000000000000026741360574160400270400ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2011-05-19 04:08:39 +1000 (Thu, 19 May 2011) $ by $Author: tack $ % $Revision: 12007 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_decreasing_bool(array[int] of var bool: x); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_decreasing_int.mzn000066400000000000000000000026721360574160400266750ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2010-03-31 19:18:34 +1100 (Wed, 31 Mar 2010) $ by $Author: tack $ % $Revision: 10618 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_decreasing_int(array[int] of var int: x); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_diffn.mzn000066400000000000000000000033501360574160400247770ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2011-06-04 01:27:50 +1000 (Sat, 04 Jun 2011) $ by $Author: tack $ % $Revision: 12041 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_nooverlap(array[int] of var int: x, array[int] of var int: w, array[int] of var int: y, array[int] of var int: h); predicate fzn_diffn(array[int] of var int: x, array[int] of var int: y, array[int] of var int: dx, array[int] of var int: dy) = gecode_nooverlap(x,dx,y,dy); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_disjoint.mzn000066400000000000000000000027041360574160400255360ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2009-09-09 01:42:03 +1000 (Wed, 09 Sep 2009) $ by $Author: schulte $ % $Revision: 9689 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_disjoint(var set of int: s1, var set of int: s2); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_distribute.mzn000066400000000000000000000035031360574160400260670ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2011-05-19 04:08:39 +1000 (Thu, 19 May 2011) $ by $Author: tack $ % $Revision: 12007 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_distribute(array[int] of var int: card, array[int] of var int: value, array[int] of var int: base) = assert(index_set(card) == index_set(value), "distribute: card and value arrays must have identical index sets", forall (i in index_set(card)) ( bool_sum_eq([value[i] == base[j] | j in index_set(base)], card[i]) ) ); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_exactly_int.mzn000066400000000000000000000027641360574160400262440ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2009-09-09 01:42:03 +1000 (Wed, 09 Sep 2009) $ by $Author: schulte $ % $Revision: 9689 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % include "count.mzn"; predicate fzn_exactly_int(int: n, array[int] of var int: x, int: v) = count(x, v, n); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_exactly_set.mzn000066400000000000000000000030151360574160400262330ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2009-09-09 01:42:03 +1000 (Wed, 09 Sep 2009) $ by $Author: schulte $ % $Revision: 9689 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_exactly_set(int: n, array[int] of var set of int: x, set of int: v) = bool_sum_eq([x[i] == v | i in index_set(x)], n); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_global_cardinality.mzn000066400000000000000000000033461360574160400275410ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2013-03-07 12:18:29 +1100 (Thu, 07 Mar 2013) $ by $Author: mears $ % $Revision: 13455 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_global_cardinality(array[int] of var int: x, array[int] of int: cover, array[int] of var int: counts); predicate global_cardinality_old(array[int] of var int: x, array[int] of var int: c) = global_cardinality(x,[i|i in index_set(c)],c); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_global_cardinality_closed.mzn000066400000000000000000000031161360574160400310650ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2011-01-14 08:42:12 +1100 (Fri, 14 Jan 2011) $ by $Author: tack $ % $Revision: 11531 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_global_cardinality_closed(array[int] of var int: x, array[int] of int: cover, array[int] of var int: counts); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_global_cardinality_low_up.mzn000066400000000000000000000032201360574160400311150ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2010-10-07 08:10:08 +1100 (Thu, 07 Oct 2010) $ by $Author: schulte $ % $Revision: 11466 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_global_cardinality_low_up(array[int] of var int: x, array[int] of int: cover, array[int] of int: lbound, array[int] of int: ubound); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_global_cardinality_low_up_closed.mzn000066400000000000000000000032511360574160400324520ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2011-05-19 04:08:39 +1000 (Thu, 19 May 2011) $ by $Author: tack $ % $Revision: 12007 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_global_cardinality_low_up_closed(array[int] of var int: x, array[int] of int: cover, array[int] of int: lbound, array[int] of int: ubound); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_increasing_bool.mzn000066400000000000000000000026761360574160400270600ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2009-09-09 01:42:03 +1000 (Wed, 09 Sep 2009) $ by $Author: schulte $ % $Revision: 9689 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_increasing_bool(array[int] of var bool: x); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_increasing_int.mzn000066400000000000000000000026741360574160400267150ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2009-09-09 01:42:03 +1000 (Wed, 09 Sep 2009) $ by $Author: schulte $ % $Revision: 9689 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_increasing_int(array[int] of var int: x); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_int_set_channel.mzn000066400000000000000000000037711360574160400270550ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2012-03-19 11:56:37 +1100 (Mon, 19 Mar 2012) $ by $Author: tack $ % $Revision: 12583 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_int_set_channel(array[int] of var int: x, int: xoff, array[int] of var set of int: y, int: yoff); predicate fzn_int_set_channel(array[int] of var int: x, array[int] of var set of int: y) = if (min(index_set(x)) < 0 \/ min(index_set(y)) < 0) then forall(i in index_set(x)) (x[i] in index_set(y)) /\ forall(j in index_set(y)) (y[j] subset index_set(x)) /\ forall(i in index_set(x), j in index_set(y)) (x[i]=j <-> i in y[j]) else gecode_int_set_channel(x,min(index_set(x)),y,min(index_set(y))) endif; libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_inverse.mzn000066400000000000000000000033001360574160400253570ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2009-09-09 01:42:03 +1000 (Wed, 09 Sep 2009) $ by $Author: schulte $ % $Revision: 9689 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_inverse_offsets(array[int] of var int: f, int: foff, array[int] of var int: invf, int: invfoff); predicate fzn_inverse(array[int] of var int: f, array[int] of var int: invf) = gecode_inverse_offsets(f, min(index_set(invf)), invf, min(index_set(f))); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_inverse_set.mzn000066400000000000000000000040471360574160400262430ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2012-03-19 11:56:37 +1100 (Mon, 19 Mar 2012) $ by $Author: tack $ % $Revision: 12583 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_inverse_set(array[int] of var set of int: f, array[int] of var set of int: invf, int: xoff, int: yoff); predicate fzn_inverse_set(array[int] of var set of int: f, array[int] of var set of int: invf) = forall(i in index_set(f)) ( f[i] subset index_set(invf) ) /\ forall(j in index_set(invf)) ( invf[j] subset index_set(f) ) /\ if (min(index_set(f)) >= 0 /\ min(index_set(invf)) >= 0) then gecode_inverse_set(f,invf,min(index_set(f)),min(index_set(invf))) else forall(i in index_set(f), j in index_set(invf)) ( (j in f[i] <-> i in invf[j]) ) endif; libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_lex_less_bool.mzn000066400000000000000000000031741360574160400265460ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2012-04-11 14:59:27 +1000 (Wed, 11 Apr 2012) $ by $Author: tack $ % $Revision: 12730 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_array_bool_lt(array[int] of var bool: x, array[int] of var bool: y); predicate fzn_lex_less_bool(array[int] of var bool: x, array[int] of var bool: y) = gecode_array_bool_lt(x,y); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_lex_less_int.mzn000066400000000000000000000032001360574160400263730ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2009-09-09 01:42:03 +1000 (Wed, 09 Sep 2009) $ by $Author: schulte $ % $Revision: 9689 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_array_int_lt(array[int] of var int: x, array[int] of var int: y); predicate fzn_lex_less_int(array[int] of var int: x, array[int] of var int: y) = gecode_array_int_lt(x,y); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_lex_lesseq_bool.mzn000066400000000000000000000032131360574160400270660ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2012-04-11 14:59:27 +1000 (Wed, 11 Apr 2012) $ by $Author: tack $ % $Revision: 12730 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_array_bool_lq(array[int] of var bool: x, array[int] of var bool: y); predicate fzn_lex_lesseq_bool(array[int] of var bool: x, array[int] of var bool: y) = gecode_array_bool_lq(x,y); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_lex_lesseq_int.mzn000066400000000000000000000032041360574160400267250ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2009-09-09 01:42:03 +1000 (Wed, 09 Sep 2009) $ by $Author: schulte $ % $Revision: 9689 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_array_int_lq(array[int] of var int: x, array[int] of var int: y); predicate fzn_lex_lesseq_int(array[int] of var int: x, array[int] of var int: y) = gecode_array_int_lq(x,y); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_link_set_to_booleans.mzn000066400000000000000000000033151360574160400301060ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2012-03-19 11:56:37 +1100 (Mon, 19 Mar 2012) $ by $Author: tack $ % $Revision: 12583 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_link_set_to_booleans(var set of int: s, array[int] of var bool: b, int: idx); predicate fzn_link_set_to_booleans(var set of int: s, array[int] of var bool: b) = if min(index_set(b)) < 0 then forall(i in index_set(b)) ( b[i] <-> i in s ) else gecode_link_set_to_booleans(s,b,min(index_set(b))) endif libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_member_bool.mzn000066400000000000000000000027051360574160400261760ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2012-03-19 11:56:37 +1100 (Mon, 19 Mar 2012) $ by $Author: tack $ % $Revision: 12583 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_member_bool(array[int] of var bool: x, var bool: y); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_member_bool_reif.mzn000066400000000000000000000032151360574160400272000ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2012-03-19 11:56:37 +1100 (Mon, 19 Mar 2012) $ by $Author: tack $ % $Revision: 12583 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_member_bool_reif(array[int] of var bool: x, var bool: y, var bool: b); predicate fzn_member_bool_reif(array[int] of var bool: x, var bool: y, var bool: b) = gecode_member_bool_reif(x,y,b); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_member_int.mzn000066400000000000000000000027021360574160400260320ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2012-03-19 11:56:37 +1100 (Mon, 19 Mar 2012) $ by $Author: tack $ % $Revision: 12583 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_member_int(array[int] of var int: x, var int: y); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_member_int_reif.mzn000066400000000000000000000032001360574160400270310ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2012-03-19 11:56:37 +1100 (Mon, 19 Mar 2012) $ by $Author: tack $ % $Revision: 12583 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_member_int_reif(array[int] of var int: x, var int: y, var bool: b); predicate member_int_reif(array[int] of var int: x, var int: y, var bool: b) = gecode_member_int_reif(x,y,b); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_nvalue.mzn000066400000000000000000000026761360574160400252150ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2011-08-18 17:42:10 +1000 (Thu, 18 Aug 2011) $ by $Author: tack $ % $Revision: 12312 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_nvalue(var int: n, array[int] of var int: x); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_partition_set.mzn000066400000000000000000000032451360574160400266000ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2009-09-09 01:42:03 +1000 (Wed, 09 Sep 2009) $ by $Author: schulte $ % $Revision: 9689 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_array_set_partition(array[int] of var set of int: S, set of int: universe); predicate fzn_partition_set(array[int] of var set of int: S, set of int: universe) = gecode_array_set_partition(S, universe); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_range.mzn000066400000000000000000000040351360574160400250060ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2012-03-19 11:56:37 +1100 (Mon, 19 Mar 2012) $ by $Author: tack $ % $Revision: 12583 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_range(array[int] of var int: x, int: xoff, var set of int: s, var set of int: t); predicate fzn_range(array[int] of var int: x, var set of int: s, var set of int: t) = assert(ub(s) subset index_set(x), "range: upper bound of 's' must be a subset of the index set of 'x'", if (min(index_set(x)) >= 0) then gecode_range(x,min(index_set(x)),s,t) else forall(i in ub(s)) (i in s -> x[i] in t) /\ forall(i in ub(t)) ( i in t -> exists(j in ub(s)) ( j in s /\ x[j] == i ) ) endif ); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_regular.mzn000066400000000000000000000030111360574160400253440ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2009-09-09 01:42:03 +1000 (Wed, 09 Sep 2009) $ by $Author: schulte $ % $Revision: 9689 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_regular(array[int] of var int: x, int: Q, int: S, array[int,int] of int: d, int: q0, set of int: F); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_roots.mzn000066400000000000000000000046361360574160400250670ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2012-03-19 11:56:37 +1100 (Mon, 19 Mar 2012) $ by $Author: tack $ % $Revision: 12583 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % include "int_set_channel.mzn"; % i in z <-> exists (j in x) (i in y[j]) predicate gecode_array_set_element_union(var set of int: x, array[int] of var set of int: y, var set of int: z); predicate fzn_roots(array[int] of var int: x, var set of int: s, var set of int: t) = assert(ub(s) subset index_set(x), "roots: upper bound of 's' must be a subset of the index set of 'x'", if (min(index_set(x)) < 0 \/ min(ub(t)) < 1) then % All values in 's' must map to a value in 't'. forall(i in ub(s)) ( i in s -> x[i] in t ) /\ % All values in 't' must be mapped from a value in 's'. forall(i in ub(t)) ( i in t -> forall(j in index_set(x)) (x[j] == i -> j in s) ) else let { array[1..max(ub(t))] of var set of 0..max(index_set(x)): y, } in int_set_channel(x,y) /\ gecode_array_set_element_union(t,y,s) endif ); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_sort.mzn000066400000000000000000000027141360574160400247030ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2009-09-09 01:42:03 +1000 (Wed, 09 Sep 2009) $ by $Author: schulte $ % $Revision: 9689 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_sort(array[int] of var int: x, array[int] of var int: y); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_sum_pred.mzn000066400000000000000000000032521360574160400255300ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2012-03-19 11:56:37 +1100 (Mon, 19 Mar 2012) $ by $Author: tack $ % $Revision: 12583 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_set_weights(array[int] of int: csi,array[int] of int: cs, var set of int: x, var int: y); predicate fzn_sum_pred(var int: i, array[int] of set of int: sets, array[int] of int: cs, var int: s) = gecode_set_weights([j|j in index_set(cs)],cs,sets[i],s); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_table_bool.mzn000066400000000000000000000027251360574160400260200ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2009-09-09 01:42:03 +1000 (Wed, 09 Sep 2009) $ by $Author: schulte $ % $Revision: 9689 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_table_bool(array[int] of var bool: x, array[int, int] of bool: t); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_table_int.mzn000066400000000000000000000030741360574160400256550ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2009-09-09 01:42:03 +1000 (Wed, 09 Sep 2009) $ by $Author: schulte $ % $Revision: 9689 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate fzn_table_int(array[int] of var int: x, array[int, int] of int: t) = fzn_table_int(x, array1d(t)); predicate fzn_table_int(array[int] of var int: x, array[int] of int: t); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_value_precede_int.mzn000066400000000000000000000030571360574160400273720ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2013-07-19 22:10:52 +1000 (Fri, 19 Jul 2013) $ by $Author: schulte $ % $Revision: 13911 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_precede(array[int] of var int: x, int: s, int: t); predicate fzn_value_precede_int(int: s, int: t, array[int] of var int: x) = gecode_precede(x,s,t); libminizinc-2.4.2/share/minizinc/gecode_presolver/fzn_value_precede_set.mzn000066400000000000000000000031051360574160400273650ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2013-07-19 22:10:52 +1000 (Fri, 19 Jul 2013) $ by $Author: schulte $ % $Revision: 13911 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_precede_set(array[int] of var set of int: x, int: s, int: t); predicate fzn_value_precede_set(int: s, int: t, array[int] of var set of int: x) = gecode_precede_set(x,s,t); libminizinc-2.4.2/share/minizinc/gecode_presolver/gecode.mzn000066400000000000000000000171261360574160400242700ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2015-01-05 17:33:06 +1100 (Mon, 05 Jan 2015) $ by $Author: tack $ % $Revision: 14337 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % /*** @groupdef gecode Additional declarations for Gecode These annotations and predicates are available for the Gecode solver. In order to use them in a model, include the file "gecode.mzn". */ /*** @groupdef gecode.annotations Additional Gecode search annotations */ /** @group gecode.annotations Select variable with smallest accumulated failure count */ annotation afc_min; /** @group gecode.annotations Select variable with smallest accumulated failure count divided by domain size */ annotation afc_size_min; /** @group gecode.annotations Select variable with largest accumulated failure count */ annotation afc_max; /** @group gecode.annotations Select variable with largest accumulated failure count divided by domain size */ annotation afc_size_max; /** @group gecode.annotations Select variable with smallest activity count */ annotation activity_min; /** @group gecode.annotations Select variable with smallest activity count divided by domain size */ annotation activity_size_min; /** @group gecode.annotations Select variable with largest activity count */ annotation activity_max; /** @group gecode.annotations Select variable with largest activity count divided by domain size */ annotation activity_size_max; /** @group gecode.annotations Select random variable */ annotation random; /** @group gecode.annotations Specify default search strategy for integer variables to use variable selection strategy \a varsel, and value choice strategy \a valsel. */ annotation int_default_search(ann: varsel, ann: valsel); /** @group gecode.annotations Specify default search strategy for Boolean variables to use variable selection strategy \a varsel, and value choice strategy \a valsel. */ annotation bool_default_search(ann: varsel, ann: valsel); /** @group gecode.annotations Specify default search strategy for set variables to use variable selection strategy \a varsel, and value choice strategy \a valsel. */ annotation set_default_search(ann: varsel, ann: valsel); /** @group gecode.annotations Specify default search strategy for float variables to use variable selection strategy \a varsel, and value choice strategy \a valsel. */ annotation float_default_search(ann: varsel, ann: valsel); /** @group gecode.annotations Simple large neighbourhood search strategy: upon restart, for each variable in \a x, the probability of it being fixed to the previous solution is \a percentage (out of 100). */ annotation relax_and_reconstruct(array[int] of var int: x, int: percentage); /** @group gecode.annotations Simple large neighbourhood search strategy: upon restart, for each variable in \a x, the probability of it being fixed to the previous solution is \a percentage (out of 100). Start from an initial solution \a y. */ annotation relax_and_reconstruct(array[int] of var int: x, int: percentage, array[int] of int: y); /*** @groupdef gecode.constraints Additional Gecode constraints */ /** @group gecode.constraints Constrain \a z to be the intersection of all sets in \a y that are selected by \a x: \(i \in \a z \leftrightarrow \forall j \in \a x: (i \in \a y[j]) \) */ predicate gecode_array_set_element_intersect(var set of int: x, array[int] of var set of int: y, var set of int: z); /** @group gecode.constraints Constrain \a z to be the disjoint union of all sets in \a y that are selected by \a x: \(i \in \a z \leftrightarrow \exists j \in \a x: (i \in \a y[j]) \) and \( i \in \a x \land j \in \a x \land i\neq j \rightarrow \a y[i] \cap \a y[j]=\emptyset \) */ predicate gecode_array_set_element_partition(var set of int: x, array[int] of var set of int: y, var set of int: z); /** @group gecode.constraints Constrain \a z to be a subset of \a u, and \a z to be the intersection of all sets in \a y that are selected by \a x: \(i \in \a z \leftrightarrow \forall j \in \a x: (i \in \a y[j]) \) */ predicate gecode_array_set_element_intersect_in(var set of int: x, array[int] of var set of int: y, var set of int: z, set of int: u); predicate gecode_among_seq_int(array[int] of var int: x, set of int: S, int: l, int: m, int: n); predicate gecode_among_seq_bool(array[int] of var bool: x, bool: b, int: l, int: m, int: n); /** @group gecode.constraints Every subsequence of \a x of length \a l has at least \a m and at most \a n occurrences of the values in \a S */ predicate among_seq(array[int] of var int: x, set of int: S, int: l, int: m, int: n) = gecode_among_seq_int(x,S,l,m,n); /** @group gecode.constraints Every subsequence of \a x of length \a l has at least \a m and at most \a n occurrences of the values in \a S */ predicate among_seq(array[int] of var bool: x, bool: b, int: l, int: m, int: n) = gecode_among_seq_bool(x,b,l,m,n); predicate gecode_circuit_cost_array(array[int] of int: c, array[int] of var int: x, array[int] of var int: y, var int: z); predicate gecode_circuit_cost(array[int] of int: c, array[int] of var int: x, var int: z); /** @group gecode.constraints Constrains the elements of \a x to define a circuit where \a x[\p i] = \p j means that \p j is the successor of \p i. Additionally, constrain \a z to be the cost of the circuit. Each edge cost is defined by array \a c. The variables \a y[i] are constrained to be the edge cost of the node \a x[i]. */ predicate circuit_cost_array(array[int] of int: c, array[int] of var int: x, array[int] of var int: y, var int: z) = gecode_circuit_cost_array(c,[x[i]-min(index_set(x)) | i in index_set(x)], y,z); /** @group gecode.constraints Constrains the elements of \a x to define a circuit where \a x[\p i] = \p j means that \p j is the successor of \p i. Additionally, constrain \a z to be the cost of the circuit. Each edge cost is defined by array \a c. */ predicate circuit_cost(array[int] of int: c, array[int] of var int: x, var int: z) = gecode_circuit_cost(c, [x[i]-min(index_set(x)) | i in index_set(x)], z); predicate gecode_schedule_unary(array[int] of var int: x, array[int] of int: p); predicate gecode_schedule_unary_optional(array[int] of var int: x, array[int] of int: p, array[int] of var bool: m); predicate gecode_schedule_cumulative_optional(array[int] of var int: start, array[int] of int: duration, array[int] of int: usage, array[int] of var bool: m, int: capacity); libminizinc-2.4.2/share/minizinc/gecode_presolver/precedence.mzn000066400000000000000000000031421360574160400251300ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2011-07-12 21:52:11 +1000 (Tue, 12 Jul 2011) $ by $Author: tack $ % $Revision: 12175 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % predicate gecode_precede(array[int] of var int: x, array[int] of int: c); predicate precedence(array[int] of var int: x) = forall (i in index_set(x)) (x[i] <= length(x)) /\ gecode_precede(x, [i|i in 1..length(x)]); libminizinc-2.4.2/share/minizinc/gecode_presolver/redefinitions-2.0.mzn000066400000000000000000000022721360574160400261750ustar00rootroot00000000000000% This file contains redefinitions of standard builtins that can be overridden % by solvers. predicate bool_clause_reif(array[int] of var bool: as, array[int] of var bool: bs, var bool: b) = clause(as,bs++[b]) /\ forall (i in index_set(as)) (as[i] -> b) /\ forall (i in index_set(bs)) (bs[i] \/ b); predicate array_int_maximum(var int: m, array[int] of var int: x); predicate array_float_maximum(var float: m, array[int] of var float: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), float: ly = lb_array(x), float: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == max(x[i],y[i-1]) ); predicate array_int_minimum(var int: m, array[int] of var int: x); predicate array_float_minimum(var float: m, array[int] of var float: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), float: ly = lb_array(x), float: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == min(x[i],y[i-1]) ); libminizinc-2.4.2/share/minizinc/gecode_presolver/redefinitions.mzn000066400000000000000000000060461360574160400257030ustar00rootroot00000000000000% % Main authors: % Guido Tack % % Copyright: % Guido Tack, 2007 % % Last modified: % $Date: 2012-04-06 16:43:44 +1000 (Fri, 06 Apr 2012) $ by $Author: tack $ % $Revision: 12706 $ % % This file is part of Gecode, the generic constraint % development environment: % http://www.gecode.org % % Permission is hereby granted, free of charge, to any person obtaining % a copy of this software and associated documentation files (the % "Software"), to deal in the Software without restriction, including % without limitation the rights to use, copy, modify, merge, publish, % distribute, sublicense, and/or sell copies of the Software, and to % permit persons to whom the Software is furnished to do so, subject to % the following conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE % LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION % OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION % WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. % % % Sums over Boolean variables predicate bool_lin_eq(array[int] of int: a, array[int] of var bool: x, var int: c); predicate bool_lin_ne(array[int] of int: a, array[int] of var bool: x, var int: c); predicate bool_lin_le(array[int] of int: a, array[int] of var bool: x, var int: c); predicate bool_lin_lt(array[int] of int: a, array[int] of var bool: x, var int: c); predicate bool_lin_ge(array[int] of int: a, array[int] of var bool: x, var int: c); predicate bool_lin_gt(array[int] of int: a, array[int] of var bool: x, var int: c); predicate bool_sum_eq(array[int] of var bool: x, var int: c) = bool_lin_eq([1 | i in index_set(x)],x,c); predicate bool_sum_ne(array[int] of var bool: x, var int: c) = bool_lin_ne([1 | i in index_set(x)],x,c); predicate bool_sum_le(array[int] of var bool: x, var int: c) = bool_lin_le([1 | i in index_set(x)],x,c); predicate bool_sum_lt(array[int] of var bool: x, var int: c) = bool_lin_lt([1 | i in index_set(x)],x,c); predicate bool_sum_ge(array[int] of var bool: x, var int: c) = bool_lin_ge([1 | i in index_set(x)],x,c); predicate bool_sum_gt(array[int] of var bool: x, var int: c) = bool_lin_gt([1 | i in index_set(x)],x,c); predicate float_sinh(var float: a, var float: b) = b == (exp(a)-exp(-a))/2.0; predicate float_cosh(var float: a, var float: b) = b == (exp(a)+exp(-a))/2.0; predicate float_tanh(var float: a, var float: b) = let { var float: e2a = exp(2.0*a) } in b == (e2a-1.0)/(e2a+1.0); predicate float_ne_reif(var float: a, var float: b, var bool: c) = not c <-> a==b; libminizinc-2.4.2/share/minizinc/linear/000077500000000000000000000000001360574160400202305ustar00rootroot00000000000000libminizinc-2.4.2/share/minizinc/linear/CHANGELOG.txt000066400000000000000000000004311360574160400222560ustar00rootroot00000000000000 2015-07-20 Special handling of array_int_element which is a linear fn. No much diff on ProjPlanning_12_8. [REVERTED] Replaced array_int_element by the old (forall(.. -> ..)) 82s vs 45s on ProjPlanning_12_8libminizinc-2.4.2/share/minizinc/linear/domain_encodings.mzn000066400000000000000000000103361360574160400242610ustar00rootroot00000000000000/*%-----------------------------------------------------------------------------% % Domain encodings %-----------------------------------------------------------------------------% */ % Linear equality encoding % Single variable: x = d <-> x_eq_d[d] predicate equality_encoding(var int: x, array[int] of var int: x_eq_d) = x in index_set(x_eq_d) /\ sum(d in dom(x))( x_eq_d[d] ) = 1 /\ sum(d in dom(x))( d * x_eq_d[d] ) = x /\ % my_trace( "eq_enc: \(x), index_set(pp)=" ++ show(index_set( x_eq_d )) ++ "\n" ) /\ if fPostprocessDomains then equality_encoding__POST(x, x_eq_d) else true endif ; % Two variables: x = d /\ y = e <-> x_eq_d[d] /\ y_eq_e[e] /\ xy_eq_de[d, e] predicate equality_encoding(var int: x, var int: y, array[int] of var int: x_eq_d, array[int] of var int: y_eq_e, array[int, int] of var int: xy_eq_de ) = x in index_set(x_eq_d) /\ y in index_set(y_eq_e) /\ index_set(x_eq_d) == index_set_1of2(xy_eq_de) /\ index_set(y_eq_e) == index_set_2of2(xy_eq_de) /\ sum(d in dom(x), e in dom(y))( xy_eq_de[d, e] ) = 1 /\ forall(d in dom(x)) (sum(e in dom(y))( xy_eq_de[d, e] ) = x_eq_d[d]) /\ forall(e in dom(y)) (sum(d in dom(x))( xy_eq_de[d, e] ) = y_eq_e[e]) ; % Array of variables: x[i] = d <-> x_eq_d[i,d] predicate equality_encoding(array[int] of var int: x, array[int, int] of var int: x_eq_d) = forall(i in index_set(x))( x[i] in index_set_2of2(x_eq_d) /\ sum(d in index_set_2of2(x_eq_d))( x_eq_d[i,d] ) = 1 /\ sum(d in index_set_2of2(x_eq_d))( d * x_eq_d[i,d] ) = x[i] ); function var int: eq_new_var(var int: x, int: i) ::promise_total = if i in dom(x) then let { var 0..1: xi; } in xi else 0 endif; function array[int] of var int: eq_encode(var int: x) ::promise_total = let { array[int] of var int: y = array1d(lb(x)..ub(x),[eq_new_var(x,i) | i in lb(x)..ub(x)]); constraint equality_encoding(x,y); % constraint % if card(dom(x))>0 then % my_trace(" eq_encode: dom(\(x)) = " ++ show(dom(x)) ++ ", card( dom(\(x)) ) = " ++ show(card(dom(x))) ++ "\n") % else true endif; %% constraint assert(card(dom(x))>1, " eq_encode: card(dom(\(x))) == " ++ show(card(dom(x)))); } in y; function array[int] of int: eq_encode(int: x) ::promise_total = array1d(lb(x)..ub(x),[ if i=x then 1 else 0 endif | i in lb(x)..ub(x)]); %%% The same for 2 variables: function var int: eq_new_var(var int: x, int: i, var int: y, int: j) ::promise_total = if i in dom(x) /\ j in dom(y) then let { var 0..1: xi; } in xi else 0 endif; function array[int, int] of var int: eq_encode(var int: x, var int: y) ::promise_total = let { array[int] of var int: pX = eq_encode(x), array[int] of var int: pY = eq_encode(y), array[int, int] of var int: pp = array2d(index_set(pX), index_set(pY), [eq_new_var(x,i,y,j) | i in index_set(pX), j in index_set(pY)]); constraint equality_encoding(x, y, pX, pY, pp); } in pp; function array[int, int] of int: eq_encode(int: x, int: y) ::promise_total = % let { % constraint if card(dom(x))*card(dom(y))>200 then % my_trace(" eq_encode: dom(\(x)) = " ++ show(dom(x)) ++ ", dom(\(y)) = " ++ show(dom(y)) ++ "\n") % else true endif; % } in array2d(lb(x)..ub(x), lb(y)..ub(y), [if i==x /\ j==y then 1 else 0 endif | i in lb(x)..ub(x), j in lb(y)..ub(y)]); function array[int,int] of var int: eq_encode(array[int] of var int: x) ::promise_total = let { array[index_set(x),lb_array(x)..ub_array(x)] of var int: y = array2d(index_set(x),lb_array(x)..ub_array(x), [ let { array[int] of var int: xi = eq_encode(x[i]) } in if j in index_set(xi) then xi[j] else 0 endif | i in index_set(x), j in lb_array(x)..ub_array(x)] ) } in y; function array[int,int] of int: eq_encode(array[int] of int: x) ::promise_total = array2d(index_set(x),lb_array(x)..ub_array(x),[ if j=x[i] then 1 else 0 endif | i in index_set(x), j in lb_array(x)..ub_array(x)]); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/linear/fzn_all_different_int.mzn000066400000000000000000000015251360574160400253060ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % 'all_different' constrains an array of objects to be all different. % % Linear version: equality encoding; see e.g. [Refalo, CP 2000] % % For a given d in dom(x), at most one i with x_i = d can exist. %-----------------------------------------------------------------------------% include "domain_encodings.mzn"; predicate fzn_all_different_int(array[int] of var int: x) = if length(x)<=1 then true else let { array[int,int] of var 0..1: x_eq_d = eq_encode(x) } in ( % my_trace(" all_different_int: x[" ++ show(index_set(x)) ++ "]\n") /\ forall(d in index_set_2of2(x_eq_d))( sum(i in index_set_1of2(x_eq_d))( x_eq_d[i,d] ) <= 1 ) ) endif; %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/linear/fzn_alldifferent_except_0.mzn000066400000000000000000000012211360574160400260550ustar00rootroot00000000000000/** @group globals.alldifferent Constrain the array of integers \a vs to be all different except those elements that are assigned the value 0. */ predicate fzn_alldifferent_except_0(array[int] of var int: vs) = % forall(i, j in index_set(vs) where i < j) ( % (vs[i] != 0 /\ vs[j] != 0) -> vs[i] != vs[j] % ); if length(vs)<=1 then true else let { array[int,int] of var 0..1: x_eq_d = eq_encode(vs) } in ( % my_trace(" alldifferent_except_0: x[" ++ show(index_set(vs)) ++ "]\n") /\ forall(d in index_set_2of2(x_eq_d) diff {0})( sum(i in index_set_1of2(x_eq_d))( x_eq_d[i,d] ) <= 1 ) ) endif; libminizinc-2.4.2/share/minizinc/linear/fzn_circuit.mzn000066400000000000000000000035031360574160400232760ustar00rootroot00000000000000include "alldifferent.mzn"; /** @group globals Constrains the elements of \a x to define a circuit where \a x[\p i] = \p j means that \p j is the successor of \p i. */ % Linear version. predicate fzn_circuit(array[int] of var int: x) = let { set of int: S = index_set(x), int: l = min(S), int: u = max(S), int: n = card(S), constraint forall( i in S )( x[i] in S diff {i} ), %% Self-mapping and exclude i->i before alldifferent } in alldifferent(x) /\ % alldifferent(order) /\ if nMZN__fSECcuts>0 then let { array [int, int] of var int: eq_x = eq_encode( x ), constraint assert( l==min( index_set_2of2( eq_x ) ), "circuit: index set mismatch" ), %% self-mapping constraint assert( u==max( index_set_2of2( eq_x ) ), "circuit: index set mismatch" ), } in circuit__SECcuts( eq_x ) else true endif /\ if nMZN__fSECcuts<2 then %%% MTZ model. Note that INTEGER order vars seem better!: let { array[l+1..l+n-1] of var 2..n: order, } in forall (i,j in l+1..l+n-1 where i!=j /\ j in dom(x[i])) ( order[i] - order[j] + (n-1)* bool2int(x[i]==j) + (n-3)*bool2int(x[j]==i) %% the Desrochers & Laporte '91 term %%%% --- strangely enough it is much worse on vrp-s2-v2-c7_vrp-v2-c7_det_ADAPT_1_INVERSE.mzn! <= n-2 ) else true endif %% ... but seems improved with this (leaving also for SEC) /\ if n>2 then forall (i,j in S where i= 0 and \a r[\p i] >= 0 Linear version. */ predicate fzn_cumulative(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = if mzn_in_redundant_constraint() /\ fMZN__IgnoreRedundantCumulative then true else let { set of int: tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 }, set of int: times = dom_array( [ s[i] | i in tasks ] ) } in if 0==card(tasks) then /*true*/ 0==card(index_set(s)) \/ b>=0 else if nMZN__UnarySizeMax_cumul>=card(times)*card(tasks) then %%% -- Mem overflow on rcmsp. PARAMETER? TODO cumulative_time_decomp(s, d, r, b, times) else cumulative_task_decomp(s, d, r, b) endif endif endif; %% Can be called with a given set of times: predicate cumulative_set_times(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b, set of int: TIMES01) = assert(index_set(s) == index_set(d) /\ index_set(s) == index_set(r), "cumulative: the 3 array arguments must have identical index sets", assert(lb_array(d) >= 0 /\ lb_array(r) >= 0, "cumulative: durations and resource usages must be non-negative", let { set of int: tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 }, set of int: times = dom_array( [ s[i] | i in tasks ] ) intersect TIMES01 } in if false then %%% 100>=card(times) then %% PARAMETER ? cumulative_time_decomp(s, d, r, b, times) else cumulative_task_decomp(s, d, r, b) endif )); predicate cumulative_time_decomp(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b, set of int: TIMES01) = let { set of int: tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 }, set of int: times = { i | i in min([ lb(s[i]) | i in tasks ]) .. max([ ub(s[i]) + ub(d[i]) | i in tasks ]) where i in TIMES01 } } in % my_trace(" cumul_time: " ++ show(card(tasks)) ++ " tasks, " ++ show(card(times)) ++ " times\n") /\ forall( t in times ) ( b >= sum( i in tasks ) ( if is_fixed(d[i]) then bool2int( s[i] in t-fix(d[i])+1..t ) else bool2int( s[i] <= t /\ t < s[i] + d[i] ) endif * r[i] ) ); predicate cumulative_task_decomp(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = let { set of int: tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 } } in % my_trace(" cumul_tasks: " ++ show(card(tasks)) ++ " tasks\n") /\ forall( j in tasks) ( b-r[j] >= sum( i in tasks where i != j /\ lb(s[i])<=ub(s[j]) /\ lb(s[j])= c[i]) /\ sum(d)=1 /\ y = sum (i in index_set(c)) ( d[i]*x[i] ); libminizinc-2.4.2/share/minizinc/linear/fzn_if_then_else_int.mzn000066400000000000000000000004271360574160400251340ustar00rootroot00000000000000predicate fzn_if_then_else_int(array[int] of var bool: c, array[int] of int: x, var int: y) = let { array[index_set(c)] of var 0..1: d; } in forall (i in index_set(c)) (sum(j in 1..i-1)(c[j])+d[i] >= c[i]) /\ sum(d)=1 /\ y = sum (i in index_set(c)) ( d[i]*x[i] ); libminizinc-2.4.2/share/minizinc/linear/fzn_inverse.mzn000066400000000000000000000022231360574160400233050ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Constrains two arrays of int variables to represent inverse functions. % All the values in each array must be within the index set of the other array. % % Linear version. %-----------------------------------------------------------------------------% % include "domain_encodings.mzn"; % predicate inverse(array[int] of var int: f, array[int] of var int: g) = % let { % array[int,int] of var 0..1: map_f = eq_encode(f); % array[int,int] of var 0..1: map_g = eq_encode(g); % } in forall (i in index_set(f), j in index_set(g)) (map_f[i,j] = map_g[j,i]); %-----------------------------------------------------------------------------% %% Now copying the std version, seems a little faster on vrp-s2-v2-c7_vrp-v2-c7_det_ADAPT_1_INVERSE.mzn predicate fzn_inverse(array[int] of var int: f, array[int] of var int: invf) = forall(i in index_set(f)) ( f[i] in index_set(invf) ) /\ forall(j in index_set(invf)) ( invf[j] in index_set(f) ) /\ forall(i in index_set(f), j in index_set(invf)) ( ((j == f[i]) <-> (i == invf[j])) ); libminizinc-2.4.2/share/minizinc/linear/fzn_lex_less_bool_reif.mzn000066400000000000000000000012461360574160400254740ustar00rootroot00000000000000include "../std/fzn_lex_less_bool_reif.mzn"; predicate fzn_lex_less_bool_imp(array[int] of var bool: x, array[int] of var bool: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = max(ux - lx, uy - ly), array[0..size+1] of var bool: b } in (c -> b[0]) /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx < uy - ly); libminizinc-2.4.2/share/minizinc/linear/fzn_lex_lesseq_bool.mzn000066400000000000000000000042401360574160400250120ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is lexicographically less than or equal to % array 'y'. Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate fzn_lex_lesseq_bool(array[int] of var bool: x, array[int] of var bool: y) = % if (min(card(index_set(x)), card(index_set(y))) <= 25) then % let { int: size = min(card(index_set(x)), card(index_set(y))); % } in % sum(i in 0..size-1)(pow(2, (size-1-i)) * bool2int(x[i+min(index_set(x))])) % <= sum(i in 0..size-1)(pow(2, (size-1-i)) * bool2int(y[i+min(index_set(y))])) % else % my_trace ("lex_lesseq_bool(\(x), \(y))") /\ let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = min(ux - lx, uy - ly), array[0..size+1] of var bool: b } % b[i] is true if the lexicographical order holds from position i on. in b[0] /\ forall(i in 0..size) ( b[i] -> ( ( ( x[lx + i] <= y[ly + i] ) ) /\ % bool2int(b[i]) + bool2int(x[lx + i]) + (1-bool2int(y[ly + i])) <= 2 /\ % ( b[i] -> ( x[lx + i] < y[ly + i] \/ b[i+1] ) ) % /\ ( bool2int(b[i]) <= bool2int(x[lx + i] < y[ly + i]) + bool2int(b[i+1]) ) /\ % bool2int(b[i]) + (1-bool2int(x[lx + i])) + (1-bool2int(y[ly + i])) + (1-bool2int(b[i+1])) <= 3 % /\ bool2int(b[i]) + bool2int(x[lx + i]) + bool2int(y[ly + i]) + (1-bool2int(b[i+1])) <= 3 %% This guy is dominated by the 1st one above but helps: % /\ bool2int(b[i]) + bool2int(x[lx + i]) + (1-bool2int(y[ly + i])) + (1-bool2int(b[i+1])) <= 3 ) /\ b[size+1] = (ux-lx <= uy-ly) % endif ; % forall(i in 0..size) ( % ( b[i] == ( x[lx + i] <= y[ly + i] ) ) % /\ % if i < size then % ( b[i] == ( x[lx + i] < y[ly + i] \/ b[i+1] % ) ) else true endif % ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/linear/fzn_lex_lesseq_bool_reif.mzn000066400000000000000000000043241360574160400260220ustar00rootroot00000000000000predicate fzn_lex_lesseq_bool_reif(array[int] of var bool: x, array[int] of var bool: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = max(ux - lx, uy - ly), array[0..size+1] of var bool: b } % b[i] is true if the lexicographical order holds from position i on. in (c <-> b[0]) /\ forall(i in 0..size) ( ( b[i] -> ( x[lx + i] <= y[ly + i] ) ) /\ bool2int(b[i]) + bool2int(x[lx + i]) + (1-bool2int(y[ly + i])) <= 2 /\ ( b[i] -> ( x[lx + i] < y[ly + i] \/ b[i+1] ) ) /\ bool2int(b[i]) + (1-bool2int(x[lx + i])) + (1-bool2int(y[ly + i])) + (1-bool2int(b[i+1])) <= 3 /\ bool2int(b[i]) + bool2int(x[lx + i]) + bool2int(y[ly + i]) + (1-bool2int(b[i+1])) <= 3 /\ bool2int(b[i]) + bool2int(x[lx + i]) + (1-bool2int(y[ly + i])) + (1-bool2int(b[i+1])) <= 3 ) /\ b[size+1] = (ux-lx <= uy-ly) % endif ; predicate fzn_lex_lesseq_bool_imp(array[int] of var bool: x, array[int] of var bool: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = max(ux - lx, uy - ly), array[0..size+1] of var bool: b } % b[i] is true if the lexicographical order holds from position i on. in (c -> b[0]) /\ forall(i in 0..size) ( ( b[i] -> ( x[lx + i] <= y[ly + i] ) ) /\ bool2int(b[i]) + bool2int(x[lx + i]) + (1-bool2int(y[ly + i])) <= 2 /\ ( b[i] -> ( x[lx + i] < y[ly + i] \/ b[i+1] ) ) /\ bool2int(b[i]) + (1-bool2int(x[lx + i])) + (1-bool2int(y[ly + i])) + (1-bool2int(b[i+1])) <= 3 /\ bool2int(b[i]) + bool2int(x[lx + i]) + bool2int(y[ly + i]) + (1-bool2int(b[i+1])) <= 3 /\ bool2int(b[i]) + bool2int(x[lx + i]) + (1-bool2int(y[ly + i])) + (1-bool2int(b[i+1])) <= 3 ) /\ b[size+1] = (ux-lx <= uy-ly) ; libminizinc-2.4.2/share/minizinc/linear/fzn_regular.mzn000066400000000000000000000107531360574160400233020ustar00rootroot00000000000000/** @group globals.extensional The sequence of values in array \a x (which must all be in the range 1..\a S) is accepted by the DFA of \a Q states with input 1..\a S and transition function \a d (which maps (1..\a Q, 1..\a S) -> 0..\a Q)) and initial state \a q0 (which must be in 1..\a Q) and accepting states \a F (which all must be in 1..\a Q). We reserve state 0 to be an always failing state. */ predicate fzn_regular(array[int] of var int: x, int: Q, int: S, array[int,int] of int: d, int: q0, set of int: F) = % my_trace(" regular: index_set(x)=" ++ show(index_set(x)) % ++ ", dom_array(x)=" ++ show(dom_array(x)) % ++ ", dom_array(a)=" ++ show(1..Q) % ++ "\n") /\ let { % If x has index set m..n-1, then a[m] holds the initial state % (q0), and a[i+1] holds the state we're in after processing % x[i]. If a[n] is in F, then we succeed (ie. accept the string). int: m = min(index_set(x)), int: n = max(index_set(x)) + 1, array[m..n] of var 1..Q: a, constraint a[m] = q0 /\ % Set a[0]. a[n] in F, % Check the final state is in F. constraint forall(i in index_set(x)) ( x[i] in 1..S % Do this in case it's a var. /\ %% trying to eliminate non-reachable states: let { set of int: va_R = { d[va, vx] | va in dom(a[i]), vx in dom(x[i]) } diff { 0 } %% Bug in MZN 2.0.4 } in a[i+1] in va_R ) } in let { constraint forall(i in [n-i | i in 1..length(x)]) ( a[i] in { va | va in dom(a[i]) where exists(vx in dom(x[i]))(d[va, vx] in dom(a[i+1])) } /\ x[i] in { vx | vx in dom(x[i]) where exists(va in dom(a[i]))(d[va, vx] in dom(a[i+1])) } ) } in forall(i in index_set(x)) ( let { set of int: va_R = { d[va, vx] | va in dom(a[i]), vx in dom(x[i]) } diff { 0 } %% Bug in MZN 2.0.4 } in % my_trace(" S" ++ show(i) % ++ ": dom(a[i])=" ++ show(dom(a[i])) % ++ ", va_R="++show(va_R) % ++ ", index_set_2of2(eq_a) diff va_R=" ++ show(index_set_2of2(eq_a) diff va_R) % ++ ", dom(a[i+1])=" ++ show(dom(a[i+1])) % ) /\ a[i+1] in va_R %/\ a[i+1] in min(va_R)..max(va_R) ) % /\ my_trace(" regular -- domains after prop: index_set(x)=" ++ show(index_set(x)) % ++ ", dom_array(x)=" ++ show(dom_array(x)) % ++ ", dom_array(a)=" ++ show(dom_array(a)) % ++ "\n") % /\ my_trace("\n") /\ let { array[int, int] of var int: eq_a=eq_encode(a), array[int, int] of var int: eq_x=eq_encode(x), } in forall(i in index_set(x)) ( % a[i+1] = d[a[i], x[i]] % Determine a[i+1]. if card(dom(a[i]))*card(dom(x[i])) > nMZN__UnarySizeMax_1step_regular then %% Implication decomposition: forall(va in dom(a[i]), vx in dom(x[i]))( if d[va, vx] in dom(a[i+1]) then eq_a[i+1, d[va, vx]] >= eq_a[i, va] + eq_x[i, vx] - 1 %% The only-if part of conj else 1 >= eq_a[i, va] + eq_x[i, vx] endif ) else %% Network-flow decomposition: %% {regularIP07} M.-C. C{\^o}t{\'e}, B.~Gendron, and L.-M. Rousseau. %% \newblock Modeling the regular constraint with integer programming. let { % array[int, int] of set of int: VX_a12 = %% set of x for given a1 that produce a2 % array2d(1..S, 1..Q, [ { vx | vx in 1..S where d[va1, vx]==va2 } | va1 in dom(a[i]), va2 in dom(a[i+1]) ]); array[int, int] of var int: ppAX = eq_encode(a[i], x[i]); } in forall (va2 in dom(a[i+1])) ( eq_a[i+1, va2] = sum(va1 in dom(a[i]), vx in dom(x[i]) where d[va1, vx]==va2) (ppAX[va1, vx]) ) /\ forall(va1 in dom(a[i]), vx in dom(x[i]))( if not (d[va1, vx] in dom(a[i+1])) then ppAX[va1, vx] == 0 else true endif ) endif ); libminizinc-2.4.2/share/minizinc/linear/fzn_sliding_sum.mzn000066400000000000000000000010561360574160400241520ustar00rootroot00000000000000/** @group globals Requires that in each subsequence \a vs[\p i], ..., \a vs[\p i + \a seq - 1] the sum of the values belongs to the interval [\a low, \a up]. */ predicate fzn_sliding_sum(int: low, int: up, int: seq, array[int] of var int: vs) = let { int: lx = min(index_set(vs)), int: ux = max(index_set(vs)), } in forall (i in lx .. ux - seq + 1) ( let { var int: sum_of_l = sum(j in i..i + seq - 1) (vs[j]) } in low <= sum_of_l /\ sum_of_l <= up ); libminizinc-2.4.2/share/minizinc/linear/fzn_subcircuit.mzn000066400000000000000000000042251360574160400240120ustar00rootroot00000000000000include "alldifferent.mzn"; /** @group globals Constrains the elements of \a x to define a subcircuit where \a x[\p i] = \p j means that \p j is the successor of \p i and \a x[\p i] = \p i means that \p i is not in the circuit. */ %% Linear version predicate fzn_subcircuit(array[int] of var int: x) = let { set of int: S = index_set(x), int: l = min(S), int: u = max(S), int: n = card(S), array[S] of var 1..n: order, array[S] of var bool: ins = array1d(S,[ x[i] != i | i in S]), var l..u+1: firstin = min([ u+1 + bool2int(ins[i])*(i-u-1) | i in S]), %% ... var S: lastin, var bool: empty = (firstin == u+1), } in alldifferent(x) /\ % NO alldifferent(order) /\ % If the subcircuit is empty then each node points at itself. % (empty <-> forall(i in S)(not ins[i])) /\ % If the subcircuit is non-empty then order numbers the subcircuit. % ((not empty) <-> %% Another way to express minimum. % forall(i in l..u+1)( % i==firstin <-> ins[i] % /\ forall(j in S where j firstin /\ % The lastin node points at firstin. x[lastin] = firstin /\ % And both are in ins[lastin] /\ ins[firstin] /\ % The successor of each node except where it is firstin is % numbered one more than the predecessor. % forall(i in S) ( % (ins[i] /\ x[i] != firstin) -> order[x[i]] = order[i] + 1 % ) /\ %%% MTZ model. Note that INTEGER order vars seem better!: forall (i,j in S where i!=j) ( order[i] - order[j] + n*bool2int( x[i]==j /\ i!=lastin ) % + (n-2)*bool2int(x[j]==i) %% the Desrochers & Laporte '91 term <= n-1 ) /\ % Each node that is not in is numbered after the lastin node. forall(i in S) ( true % (not ins[i]) <-> (n == order[i]) ) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/linear/fzn_table_int.mzn000066400000000000000000000013471360574160400236010ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % A 'table' constraint table(x, T) represents the constraint x in T where we % consider each row in T to be a tuple and T as a set of tuples. % % Linear version. % % See also the equality encoding of the 'element' constraint. %-----------------------------------------------------------------------------% predicate fzn_table_int(array[int] of var int: x, array[int, int] of int: t) = let { set of int: it = index_set_1of2(t), array[it] of var 0..1: lambda } in sum(lambda) = 1 /\ forall(j in index_set(x))( sum(i in it)( t[i,j]*lambda[i] ) = x[j] ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/linear/options.mzn000066400000000000000000000166601360574160400224620ustar00rootroot00000000000000/* % Controls % */ %-----------------------------------------------------------------------------% %---------- USER and LAZY CUTS -----------------------------------------------% /* PLEASE NOTE: If you export FZN file with lazy_constraint/user_cut annotations, their declarations are not exported currently (as of 7.11.17). WORKAROUND: when solving that fzn, add -G linear, e.g., as follows: mzn-cplex -G linear model.fzn * For Gurobi, the constraints marked as MIP_cut and/or MIP_lazy are added * into the overall model and marked with the foll values of Lazy attribute: * ::MIP_lazy 1 * ::MIP_cut ::MIP_lazy 2 * ::MIP_cut 3 */ ann: user_cut; ann: lazy_constraint; %%% comment away the below assignments (leaving, e.g., ann: MIP_cut;) to have them as normal constraints %%% In particular, they may be used by redundant_constraint() and symmetry_breaking_constraint(), see redefs-2.0.2.mzn ann: MIP_cut = user_cut; %% MIP_cut: make sure no feasible solutions are cut off %% -- seems better on average but in CPLEX, wrong LB e.g. on carpet-cutting ann: MIP_lazy = lazy_constraint; %-----------------------------------------------------------------------------% opt bool: fIndConstr; bool: fMZN__UseIndicators = %% Pass on indicator constraints if absent( fIndConstr ) then false else deopt( fIndConstr ) endif; %% CPLEX 12.6.2 Concert: reifs give wrong result on 2012/amaze, so using implications only %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Subtour elimination in circuit %%%%%%%%%%%%%%%%%%%%%%%%%%%%% % --------------------------------------------------------------------------------------- % opt int: nSECcuts; %% 0,1: use MTZ formulation int: nMZN__fSECcuts = %% 1,2: pass on circuit constraints to the MIP_solverinstance's cut gen if absent( nSECcuts ) then 0 else deopt( nSECcuts ) endif; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% MIPdomains %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % --------------------------------------------------------------------------------------- % %% Paper: % Belov, Stuckey, Tack, Wallace. Improved Linearization of Constraint Programming Models. CP 2016 Proceedings. %%% The below option enables translation of domain constraints into the ...POST predicates. %%% The code in MIPdomains.cpp processes them and also non-contiguous domains %%% (only-range-domains is then standardly off). MIPdomains.cpp needs all the required %%% __POST predicates to be declared to kick in. opt bool: fMIPDomains; %% unified decomposition constraints (...__POST) to FlatZinc opt bool: fMIPdomains; %% Can be defined from cmdline: -D "fMIPdomains=false" bool: fPostprocessDomains = %% True to pass all domain-related if absent( fMIPdomains ) /\ absent( fMIPDomains ) then true elseif not absent( fMIPdomains ) then deopt( fMIPdomains ) else deopt( fMIPDomains ) endif; opt bool: fMIPdomAux; bool: fPostproDom_AUX = %% Specialized for aux_ constr if absent( fMIPdomAux ) then false else deopt( fMIPdomAux ) endif; opt bool: fMIPdomDiff; bool: fPostproDom_DIFF = %% Specialized for differences: x z=x-y<0 if absent( fMIPdomDiff ) then false %% seems best for Gurobi, worse for CBC else deopt( fMIPdomDiff ) endif; mzn_opt_only_range_domains = not fPostprocessDomains; %% currently unused %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Avoid creating new int vars %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % --------------------------------------------------------------------------------------- % opt bool: fAvoidNewInts; bool: fAvoidNI = %% Actually this is only for ..._lin_..., not for just x-y if absent( fAvoidNewInts ) then false else deopt( fAvoidNewInts ) endif; opt bool: fNewVarsInAuxEq; bool: fAuxIntEqOLD00 = if absent(fNewVarsInAuxEq) then false else deopt(fNewVarsInAuxEq) endif; bool: fAuxFloatEqOLD00 = if absent(fNewVarsInAuxEq) then false else deopt(fNewVarsInAuxEq) endif; %%%%%%%%%%%%%%%%%%%%% Redundant constraints ---------------------------------------------- % bool: fMZN__IgnoreRedundantCumulative=false; %% NOT WORKING NOW, use redefs_2.0.2.mzn: %%%%% bool: fMZN__IgnoreAllUserRedundant=false; %% ignore all user-spec redundant constr %%%%%%%%%%%%%%%%%%%%% Element, minimuum convex hull --------------------------------------- % opt bool: fXBZCuts01; %% orders 0, 1 opt bool: fXBZCutGen; %% only works if Cuts01 bool: fElementCutsXZ=false; %% Use simple XZ & XZB cuts for element bool: fElementCutsXZB = if absent(fXBZCuts01) then false else deopt(fXBZCuts01) endif; bool: fMinimumCutsXZ=false; %% Use simple XZ & XZB cuts for minimum bool: fMinimumCutsXZB = if absent(fXBZCuts01) then false else deopt(fXBZCuts01) endif; bool: fUseXBZCutGen = if absent(fXBZCutGen) then false else deopt(fXBZCutGen) endif; % ----------------------------------------------------------------------------------------- % bool: fIntTimesBool=true; %% Special handling of multiplication with a boolean(*const) %-----------------------------------------------------------------------------% % If not postprocessing domains: For unary encoding: maximal domain length to invoke it int: nMZN__UnarySizeMax_intTimes=20; int: nMZN__UnarySizeMax_cumul=2000; int: nMZN__UnarySizeMax_1step_regular=20000; %% network-flow decomp in the regular constraint int: nMZN__UnaryLenMin__ALL=1; %% can be used by the indiv. cases int: nMZN__UnaryLenMax__ALL=2000; %% can be used by the indiv. cases % Some more detailed parameters int: nMZN__UnaryLenMin_leq = 1; int: nMZN__UnaryLenMin_neq = nMZN__UnaryLenMin__ALL; int: nMZN__UnaryLenMin_eq = nMZN__UnaryLenMin__ALL; int: nMZN__UnaryLenMax_leq = -1; int: nMZN__UnaryLenMax_neq = nMZN__UnaryLenMax__ALL; int: nMZN__UnaryLenMax_eq = nMZN__UnaryLenMax__ALL; int: nMZN__UnaryLenMax_setIn = nMZN__UnaryLenMax__ALL; int: nMZN__UnaryLenMax_setInReif = nMZN__UnaryLenMax__ALL; %-----------------------------------------------------------------------------% % Strict inequality % The relative epsilon %%% Has the problem that when relating to upper bound of various differences, %%% getting different absolute eps...? %% float: float_lt_EPS_coef__ = 1e-03; ABANDONED 12.4.18 due to #207 %%% Absolute one, used everywhere %%% Might make no sense for floats with smaller domains etc. opt float: float_EPS; float: float_lt_EPS = if absent( float_EPS ) then 1e-6 else deopt( float_EPS ) endif; %-----------------------------------------------------------------------------% %%% Set =true to PRINT TRACING messages for some constraints: opt bool: fMIPTrace; bool: mzn__my_trace_on = if absent( fMIPTrace ) then false else deopt( fMIPTrace ) endif; test my_trace(string: msg) ::promise_total = if mzn__my_trace_on then trace(msg) else true endif; test my_trace(string: msg, bool: bb) ::promise_total = if mzn__my_trace_on then trace(msg, bb) else bb endif; function var bool: my_trace(string: msg, var bool: bb) ::promise_total = if mzn__my_trace_on then trace(msg, bb) else bb endif; %%% Set =true to PRINT TRACING messages for the currently debugged constraints: opt bool: fMIPTraceDBG; bool: mzn__my_trace__DBG_on = if absent( fMIPTraceDBG ) then false else deopt( fMIPTraceDBG ) endif; test my_trace__DBG(string: msg) ::promise_total = if mzn__my_trace__DBG_on then trace(msg) else true endif; libminizinc-2.4.2/share/minizinc/linear/redefinitions-2.0.2.mzn000066400000000000000000000022661360574160400242630ustar00rootroot00000000000000% This file contains redefinitions of standard builtins for version 2.0.2 % that can be overridden by solvers. predicate symmetry_breaking_constraint(var bool: b) = (b) %:: MIP_lazy %:: MIP_cut %% MIP_cut wrong in CPLEX 12.6.3 %% Symm breaking as lazy is 1% better in Gurobi 6.5.2 on the Challenges 2012-2015 %% But caused a bug in 7.5.1 - switched off %% true %% TO omit all symmetry_breaking_constraint's ; %% Make sure no feasible solutions are cut off: predicate redundant_constraint(var bool: b) = (b) %:: MIP_cut % true %% To omit all redundant_constraint's ; %% Linearized element: just call without shifting predicate array_var_bool_element_nonshifted(var int: idx, array[int] of var bool: x, var bool: c) = array_var_bool_element(idx,x,c); predicate array_var_int_element_nonshifted(var int: idx, array[int] of var int: x, var int: c) = array_var_int_element(idx,x,c); predicate array_var_float_element_nonshifted(var int: idx, array[int] of var float: x, var float: c) = array_var_float_element(idx,x,c); predicate array_var_set_element_nonshifted(var int: idx, array[int] of var set of int: x, var set of int: c) = array_var_set_element(idx,x,c); libminizinc-2.4.2/share/minizinc/linear/redefinitions-2.0.mzn000066400000000000000000000027471360574160400241270ustar00rootroot00000000000000predicate bool_clause_reif(array[int] of var bool: p, array[int] of var bool: n, var bool: c) = c = ( sum(i in index_set(p))( bool2int(p[i]) ) - sum(i in index_set(n))( bool2int(n[i]) ) + length(n) >= 1 ); predicate array_float_minimum(var float: m, array[int] of var float: x) = if false then array_float_minimum__IND(m, x) %% transfer to Concert because of prepro else array_float_minimum_I( m, [ x[i] | i in index_set(x)]) endif; predicate array_float_maximum(var float: m, array[int] of var float: x) = if false then array_float_maximum__IND(m, x) else array_float_minimum_I(-m, [-x[i] | i in index_set(x)]) endif; predicate array_int_minimum(var int: m, array[int] of var int: x) = if false then array_int_minimum__IND(m, x) else array_float_minimum_I( int2float(m), [ int2float(x[i]) | i in index_set(x)]) endif; predicate array_int_maximum(var int: m, array[int] of var int: x) = if false then array_int_maximum__IND(m, x) else array_float_minimum_I(-int2float(m), [-int2float(x[i]) | i in index_set(x)]) endif; % predicate array_int_maximum__OLD_SYMMETRIES(var int: m, array[int] of var int: x) = % let { int: l = min(index_set(x)), % int: u = max(index_set(x)), % int: ly = lb_array(x), % int: uy = ub_array(x), % array[l..u] of var ly..uy: y } in % y[l] = x[l] /\ % m = y[u] /\ % forall (i in l+1 .. u) ( y[i] == max(x[i],y[i-1]) ); libminizinc-2.4.2/share/minizinc/linear/redefinitions-2.2.1.mzn000066400000000000000000000004001360574160400242500ustar00rootroot00000000000000% This file contains redefinitions of standard builtins for version 2.2.1 % that can be overridden by solvers. /** @group flatzinc.int Constrains \a z = \(\a x ^ {\a y}\) */ predicate int_pow_fixed(var int: x, int: y, var int: z) = int_pow( x, y, z ); libminizinc-2.4.2/share/minizinc/linear/redefinitions.mzn000066400000000000000000000607031360574160400236260ustar00rootroot00000000000000/* % FlatZinc built-in redefinitions for linear solvers. % % AUTHORS % Sebastian Brand % Gleb Belov (2015-) % cf. Belov, Stuckey, Tack, Wallace. Improved Linearization of Constraint Programming Models. CP 2016. */ %----------------------------- BOOL2INT --------------------------------% function var bool: reverse_map(var int: x) = (x==1); function bool: reverse_map(int: x) = (x==1); predicate mzn_reverse_map_var(var bool: b) = let { var int: x = bool2int(b) } in true; function var int: bool2int(var bool: x) :: promise_total = let { var 0..1: b2i; constraint (x = reverse_map(b2i)) ::is_reverse_map ; } in b2i; predicate bool_eq(var bool: x, var bool: y) = %% trace(" bool_eq: \(x), \(y) \n") /\ bool2int(x)==bool2int(y); predicate bool2int(var bool: x, var int: y) = y = bool2int(x); %---------------------------- BASIC (HALF)REIFS -----------------------------% include "options.mzn"; include "redefs_bool_reifs.mzn"; include "redefs_bool_imp.mzn"; include "domain_encodings.mzn"; include "redefs_lin_reifs.mzn"; include "redefs_lin_imp.mzn"; include "redefs_lin_halfreifs.mzn"; include "nosets.mzn"; %% For set_le, set_lt ... Usind std/nosets %% as long as the linearization is good. %-----------------------------------------------------------------------------% % Strict inequality % Uncomment the following redefinition for FlatZinc MIP solver interfaces that % do not support strict inequality. Note that it does not preserve equivalence % (some solutions of the original problem may become invalid). predicate float_lt(var float: x, var float: y) = % (x - y) <= (-float_lt_EPS_coef__)*max(abs(ub(x - y)), abs(ub(y-x))); x <= y - float_lt_EPS; predicate float_lin_lt(array[int] of float: c, array[int] of var float: x, float: d) = float_lt(sum(i in index_set(x))( c[i]*x[i] ), d); %-----------------------------------------------------------------------------% % Minimum, maximum, absolute value % Use unary as well? TODO predicate int_abs(var int: x, var int: z) = %% The simplifications seem worse on league.mzn model90-18-20.dzn: %% but the .lp seem to differ just by order...?? TODO if lb(x)>=0 then z==x elseif ub(x)<=0 then z==-x else let { var bool: p } in z >= x /\ z >= -x /\ z >= 0 /\ % This is just for preprocessor z <= max([ub(x), -lb(x)]) /\ % And this % z <= x \/ z <= -x %% simple aux_int_le_if_1(z, x, p) /\ %% even simpler aux_int_le_if_0(z, -x, p) /\ int_le_reif(0, x, p) % with reifs %int_eq_reif(z, x, p) /\ %int_eq_reif(z, -x, not p) endif ; predicate int_min(var int: x, var int: y, var int: z) = array_int_minimum(z, [x, y]); predicate int_max(var int: x, var int: y, var int: z) = array_int_maximum(z, [x, y]); predicate float_abs(var float: x, var float: z) = if lb(x)>=0.0 then z==x elseif ub(x)<=0.0 then z==-x else let { var bool: p } in z >= x /\ z >= -x /\ z >= 0.0 /\ % This is just for preprocessor z <= max([ub(x), -lb(x)]) /\ % And this % z <= x \/ z <= -x aux_float_le_if_1(z, x, (p)) /\ aux_float_le_if_0(z, -x, (p)) % /\ % float_le_reif(0.0, x, p) % with reifs - no point for floats? TODO % float_eq_reif(z, x, p) /\ % float_eq_reif(z, -x, not p) endif; predicate float_min(var float: x, var float: y, var float: z) = array_float_minimum(z, [x, y]); predicate float_max(var float: x, var float: y, var float: z) = array_float_maximum(z, [x, y]); predicate array_float_minimum_I(var float: m, array[int] of var float: x) = let { int: n = length(x), constraint assert(1 == min(index_set(x)), " array_float_minimum_I: argument indexed not from 1??"), int: iMinUB = arg_min([ub(x[i]) | i in 1..n]), float: MinUB = ub(x[iMinUB]), set of int: sLBLess = { i | i in 1..n where lb(x[i])0 then sLBLess else sLBLess union { iMinUB } endif, } in if 1==card(sActive) then m == x[min(sActive)] else let { array[1..n] of var int: p = [ if i in sActive then let { var 0..1: pi } in pi else 0 endif | i in 1..n ], constraint 1==sum(p), constraint m >= lb_array(x), constraint m <= MinUB, } in forall (i in index_set(x)) ( if i in sActive %% for at least 1 element then m<=x[i] /\ aux_float_ge_if_1(m, x[i], p[i]) else true endif ) %% -- exclude too big x[i] /\ if card(sActive)>1 /\ fMinimumCutsXZ then let { array[int] of float: AL = [ lb(x[i]) | i in 1..n], array[int] of int: srt = sort_by([i | i in 1..n], AL), %indices of lb in sorted order array[int] of float: AL_srt = [AL[srt[i]] | i in 1..n], array[int] of float: AU_srt = [ub(x[srt[i]]) | i in 1..n], array[int] of float: AM_srt = AL_srt ++ [MinUB] %% -- these are z-levels of extreme points } in forall (i in 2..n+1 where AM_srt[i]<=MinUB /\ %% this is a new "start level" AM_srt[i]!=AM_srt[i-1] )( %% and would produce a new cut m >= AM_srt[i] - sum(j in 1..i-1 where AL_srt[j]1 /\ fMinimumCutsXZB then array_var_float_element__XBZ_lb([ -x[i] | i in sActive ], [ p[i] | i in sActive ], -m) :: MIP_cut else true endif endif ; %-----------------------------------------------------------------------------% % Multiplication and division predicate int_div(var int: x, var int: y, var int: q) = q == aux_int_division_modulo_fn(x,y)[1]; predicate int_mod(var int: x, var int: y, var int: r) = r == aux_int_division_modulo_fn(x,y)[2]; function array[int] of var int: aux_int_division_modulo_fn(var int: x, var int: y) = let { %% Domain of q set of int: dom_q = if lb(y)*ub(y)>0 then let { set of int: EP = { ub(x) div ub(y), ub(x) div lb(y), lb(x) div ub(y), lb(x) div lb(y) }, } in min(EP)..max(EP) else let { int: mm = max( abs(lb(x)), abs(ub(x)) ), } in -mm..mm %% TODO case when -1 or 1 not in dom(x) endif, var dom_q: q; int: by = max(abs(lb(y)), abs(ub(y))); var -by+1..by-1: r; constraint x = y * q + r, constraint 0 <= x -> 0 <= r, %% which is 0 > x \/ 0 <= r constraint x < 0 -> r <= 0, %% which is x >= 0 \/ r <= 0 % abs(r) < abs(y) var 1.. max(abs(lb(y)), abs(ub(y))): w = abs(y), constraint w > r /\ w > -r, } in [ q, r ]; %% Can also have int_times(var float, var int) ......... TODO predicate int_times(var int: x, var int: y, var int: z) = if is_fixed(x) then z==fix(x)*y %%%%% Need to use fix() otherwise added to map & nothing happens elseif is_fixed(y) then z==x*fix(y) else if 0..1==dom(x) /\ 0..1==dom(y) then bool_and__INT(x,y,z) elseif card(dom(x))==2 /\ card(dom(y))==2 /\ 0 in dom(x) /\ 0 in dom(y) then let { var 0..1: xn; var 0..1: yn; var 0..1: zn; constraint x=xn*max(dom(x) diff {0}); constraint y=yn*max(dom(y) diff {0}); constraint z=zn*max(dom(x) diff {0})*max(dom(y) diff {0}); } in bool_and__INT(xn,yn,zn) elseif card(dom(x)) * card(dom(y)) > nMZN__UnarySizeMax_intTimes \/ ( fIntTimesBool /\ ( %% Peter's idea for *bool. More optimal but worse values on carpet cutting. (card(dom(x))==2 /\ 0 in dom(x)) \/ (card(dom(y))==2 /\ 0 in dom(y)) ) ) then %% PARAM %% ALSO NO POINT IF <=4. TODO if card(dom(x)) > card(dom(y)) \/ ( card(dom(x))==card(dom(y)) /\ 0 in dom(y) /\ not (0 in dom(x)) ) then int_times(y,x,z) else let { set of int: s = lb(x)..ub(x), set of int: r = {lb(x)*lb(y), lb(x)*ub(y), ub(x)*lb(y), ub(x)*ub(y)}, array[s] of var min(r)..max(r): ady = array1d(s, [ if d in dom(x) then d*y else min(r) endif | d in s ]) } in ady[x] = z %% use element() endif else int_times_unary(x, { }, y, z) endif endif; %% domx__ can be used to narrow domain... NOT IMPL. predicate int_times_unary(var int: x, set of int: domx__, var int: y, var int: z) = let { set of int: r = {lb(x)*lb(y), lb(x)*ub(y), ub(x)*lb(y), ub(x)*ub(y)}, %% set of int: domx = if card(domx__)>0 then domx__ else dom(x) endif, array[int, int] of var int: pp=eq_encode(x, y) } in z>=min(r) /\ z<=max(r) /\ z==sum(i in index_set_1of2(pp), j in index_set_2of2(pp)) (i * j * pp[i, j]) /\ forall(i in index_set_1of2(pp), j in index_set_2of2(pp) where not ((i*j) in dom(z)) )(pp[i, j]==0) ; predicate int_times_unary__NOFN(var int: x, set of int: domx__, var int: y, var int: z) = let { set of int: r = {lb(x)*lb(y), lb(x)*ub(y), ub(x)*lb(y), ub(x)*ub(y)}, %% set of int: domx = if card(domx__)>0 then domx__ else dom(x) endif, array[int] of var int: pX = eq_encode(x), array[int] of var int: pY = eq_encode(y), array[int] of int: valX = [ v | v in index_set(pX) ], %% NOT domx. array[int] of int: valY = [ v | v in index_set(pY) ], %% -- according to eq_encode! array[index_set(valX), index_set(valY)] of var 0..1: pp %% both dim 1.. } in if is_fixed(x) \/ is_fixed(y) then z==x*y else z>=min(r) /\ z<=max(r) /\ sum(pp)==1 /\ z==sum(i in index_set(valX), j in index_set(valY)) (valX[i] * valY[j] * pp[i, j]) /\ forall(i in index_set(valX)) ( pX[valX[i]] == sum(j in index_set(valY))( pp[i, j] ) ) /\ forall(j in index_set(valY)) ( pY[valY[j]] == sum(i in index_set(valX))( pp[i, j] ) ) endif; predicate float_times(var float: a, var float: b, var float: c) = abort("Unable to create linear formulation for the `float_times` constraint. This model instance cannot be solved using a linear solver."); %%%Define int_pow predicate int_pow( var int: x, var int: y, var int: r ) = let { array[ int, int ] of int: x2y = array2d( lb(x)..ub(x), lb(y)..ub(y), [ pow( X, Y ) | X in lb(x)..ub(x), Y in lb(y)..ub(y) ] ) } in r == x2y[ x, y ]; %%% Adding a version returning float for efficiency /** @group builtins.arithmetic Return \(\a x ^ {\a y}\) */ function var float: pow_float(var int: x, var int: y) = let { int: yy = if is_fixed(y) then fix(y) else -1 endif; } in if yy = 0 then 1 elseif yy = 1 then x else let { var float: r ::is_defined_var; constraint int_pow_float(x,y,r) ::defines_var(r); } in r endif; %%%Define int_pow_float predicate int_pow_float( var int: x, var int: y, var float: r ) = let { array[ int, int ] of float: x2y = array2d( lb(x)..ub(x), lb(y)..ub(y), [ pow( X, Y ) | X in lb(x)..ub(x), Y in lb(y)..ub(y) ] ) } in r == x2y[ x, y ]; %-----------------------------------------------------------------------------% % Array 'element' constraints predicate array_bool_element(var int: x, array[int] of bool: a, var bool: z) = array_int_element(x, arrayXd(a, [bool2int(a[i]) | i in index_set(a)]), bool2int(z)); predicate array_var_bool_element(var int: x, array[int] of var bool: a, var bool: z) = array_var_int_element(x, arrayXd(a, [bool2int(a[i]) | i in index_set(a)]), bool2int(z)); predicate array_int_element(var int: x, array[int] of int: a, var int: z) = let { constraint x in { i | i in index_set(a) where a[i] in dom(z) }, } in array_float_element(x, arrayXd(a, [int2float(a[i]) | i in index_set(a)]), int2float(z)); predicate array_var_int_element(var int: x, array[int] of var int: a, var int: z) = let { constraint x in { i | i in index_set(a) where 0 < card(dom(a[i]) intersect dom(z)) }, } in %%%% Relate to the float version: array_var_float_element(x, arrayXd(a, [int2float(a[i]) | i in index_set(a)]), int2float(z)); %%%% Simplistic version: %%%% Complete binarization: MEMORY FULL. Need exact domains & sparse encoding predicate array_float_element(var int: i00, array[int] of float: a, var float: z) = let { set of int: ix = index_set(a), constraint i00 in { i | i in ix where a[i]>=lb(z) /\ a[i]<=ub(z) }, } in %%% Finish domain before dMin/dMax let { float: dMin = min(i in dom(i00))(a[i]), float: dMax = max(i in dom(i00))(a[i]), } in if dMin==dMax then z==dMin else z >= dMin /\ z <= dMax /\ let { int: nUBi00 = max(dom(i00)), int: nLBi00 = min(dom(i00)), float: nMinDist = min(i in nLBi00 .. nUBi00-1)(a[i+1]-a[i]), float: nMaxDist = max(i in nLBi00 .. nUBi00-1)(a[i+1]-a[i]), } in if nMinDist == nMaxDist then %% The linear case z == a[nLBi00] + nMinDist*(i00-nLBi00) else let { array[int] of var int: p = eq_encode(i00) %% this needs i00 in ix } in assert(dom(i00) subset index_set(p), "", true) /\ sum(i in dom(i00))( a[i] * int2float(p[i]) ) == z %% add more hull? endif endif; predicate array_var_float_element(var int: i00, array[int] of var float: a, var float: z) = let { set of int: ix = index_set(a), constraint i00 in { i | i in ix where lb(a[i])<=ub(z) /\ ub(a[i])>=lb(z) }, } in %% finish domain first let { float: minLB=min(i in dom(i00))(lb(a[i])), float: maxUB=max(i in dom(i00))(ub(a[i])) } in if minLB==maxUB then z==minLB else z >= minLB /\ z <= maxUB /\ if {0,1}==dom(i00) /*ub(i00)-lb(i00)==1*/ /*2==card( dom( i00 ) )*/ then aux_float_eq_if_1(z, a[lb(i00)], (ub(i00)-i00)) /\ aux_float_eq_if_1(z, a[ub(i00)], (i00-lb(i00))) else let { array[int] of var int: p = eq_encode(i00), } in assert(dom(i00) subset index_set(p), "", true) /\ %%% The convexified bounds seem slow for ^2 and ^3 equations: % sum(i in dom(i01))( lb(a[i]) * int2float(p[i]) ) <= z /\ %% convexify lower bounds % sum(i in dom(i01))( ub(a[i]) * int2float(p[i]) ) >= z /\ %% convexify upper bounds forall (i in dom(i00))( aux_float_eq_if_1(z, a[i], p[i]) ) %% Cuts: /\ if fElementCutsXZ then array_var_float_element__ROOF([ a[i] | i in dom(i00) ], z) :: MIP_cut %% these 2 better as user cuts - too slow /\ array_var_float_element__ROOF([ -a[i] | i in dom(i00) ], -z) :: MIP_cut %% or even skip them else true endif /\ if fElementCutsXZB then array_var_float_element__XBZ_lb([ a[i] | i in dom(i00) ], [ p[i] | i in dom(i00) ], z) :: MIP_cut /\ array_var_float_element__XBZ_lb([ -a[i] | i in dom(i00) ], [ p[i] | i in dom(i00) ], -z) :: MIP_cut else true endif endif endif; %%% Facets on the upper surface of the z-a polytope %%% Possible parameter: maximal number of first cuts taken only predicate array_var_float_element__ROOF(array[int] of var float: a, var float: z) = let { set of int: ix = index_set(a), int: n = length(a), array[int] of float: AU = [ ub(a[i]) | i in 1..n], array[int] of int: srt_ub = sort_by([i | i in 1..n], AU), %indices of ub sorted up array[int] of float: AU_srt_ub = [ub(a[srt_ub[i]]) | i in 1..n], array[int] of float: AL_srt_ub = [lb(a[srt_ub[i]]) | i in 1..n], array[int] of float: MaxLBFrom = [ max(j in index_set(AL_srt_ub) where j>=i)(AL_srt_ub[j]) | i in 1..n ], %% direct, O(n^2) array[int] of float: ULB = [ if 1==i then MaxLBFrom[1] else max([AU_srt_ub[i-1], MaxLBFrom[i]]) endif | i in 1..n ] } in %%% "ROOF" forall (i in 1..n where if i==n then true else ULB[i]!=ULB[i+1] endif %% not the same base bound )( z <= ULB[i] + sum( j in i..n where AU_srt_ub[i] != AL_srt_ub[i] ) %% not a const ( (AU_srt_ub[j]-ULB[i]) * (a[srt_ub[j]]-AL_srt_ub[j]) / (AU_srt_ub[j]-AL_srt_ub[j]) ) ) ; predicate array_var_float_element__XBZ_lb(array[int] of var float: x, array[int] of var int: b, var float: z) = if fUseXBZCutGen then array_var_float_element__XBZ_lb__cutgen(x, b, z) :: MIP_cut else %% Adding some cuts a priori, also to make solver extract the variables let { int: i1 = min(index_set(x)) } in (z <= sum(i in index_set(x))(ub(x[i]) * b[i])) %:: MIP_cut -- does not work to put them here TODO /\ forall(i in index_set(x) intersect i1..(i1+19)) %% otherwise too many on amaze2 ( assert(lb(x[i]) == -ub(-x[i]) /\ ub(x[i]) == -lb(-x[i]), " negated var's bounds should swap " ) /\ z <= x[i] + sum(j in index_set(x) where i!=j)((ub(x[j])-lb(x[i]))*b[j])) %:: MIP_cut %% (ub_j-lb_i) * b_j /\ forall(i in index_set(x) intersect i1..(i1+19)) ( z <= ub(x[i])*b[i] + sum(j in index_set(x) where i!=j)(x[j]+lb(x[j])*(b[j]-1)) ) %:: MIP_cut /\ (z <= sum(i in index_set(x))(x[i] + lb(x[i]) * (b[i]-1))) %:: MIP_cut endif; %-----------------------------------------------------------------------------% % Set constraints %% ----------------------------------------------- (NO) SETS ---------------------------------------------- % XXX only for a fixed set here, general see below. % Normally not called because all plugged into the domain. % Might be called instead of set_in(x, var set of int s) if s gets fixed? predicate set_in(var int: x, set of int: s__) = let { set of int: s = if has_bounds(x) then s__ intersect dom(x) else s__ endif, constraint min(s) <= x, constraint x <= max(s), } in if s = min(s)..max(s) then true elseif fPostprocessDomains then set_in__POST(x, s) else %% Update eq_encode let { array[int] of var int: p = eq_encode(x); } in forall(i in index_set(p) diff s)(p[i]==0) % let { % array[int] of int: sL = [ e | e in s where not (e - 1 in s) ]; % array[int] of int: sR = [ e | e in s where not (e + 1 in s) ]; % array [index_set(sR)] of var 0..1: B; % constraint assert(length(sR)==length(sL), "N of lb and ub of sub-intervals of a set should be equal"); % } in % sum(B) = 1 %% use indicators % /\ % x >= sum(i in index_set(sL))(B[i]*sL[i]) % /\ % x <= sum(i in index_set(sR))(B[i]*sR[i]) endif; %%% for a fixed set predicate set_in_reif(var int: x, set of int: s__, var bool: b) = if is_fixed(b) then if fix(b) then x in s__ else x in dom(x) diff s__ endif elseif has_bounds(x) /\ not (s__ subset dom(x)) then b <-> x in s__ intersect dom(x) %% Use CSE else let { set of int: s = if has_bounds(x) then s__ intersect dom(x) else s__ endif, } in ( if dom(x) subset s then b==true elseif card(dom(x) intersect s)==0 then b==false elseif fPostprocessDomains then set_in_reif__POST(x, s, b) %% Bad. Very much so for CBC. 27.06.2019: elseif s == min(s)..max(s) then %% b <-> (min(s) <= x /\ x <= max(s)) else if card(dom(x))<=nMZN__UnaryLenMax_setInReif then %% PARAM TODO let { array[int] of var int: p = eq_encode(x); } in sum(i in s intersect dom(x))(p[i]) == bool2int(b) else bool2int(b) == fVarInBigSetOfInt(x, s) endif endif ) endif; % Alternative predicate alt_set_in_reif(var int: x, set of int: s, var bool: b) = b <-> exists(i in 1..length([ 0 | e in s where not (e - 1 in s) ]))( let { int: l = [ e | e in s where not (e - 1 in s) ][i], int: r = [ e | e in s where not (e + 1 in s) ][i] } in l <= x /\ x <= r ); %%% for a fixed set predicate set_in_imp(var int: x, set of int: s__, var bool: b) = if is_fixed(b) then if fix(b) then x in s__ else true endif elseif has_bounds(x) /\ not (s__ subset dom(x)) then b -> x in s__ intersect dom(x) %% Use CSE else let { set of int: s = if has_bounds(x) then s__ intersect dom(x) else s__ endif, } in ( if dom(x) subset s then true elseif card(dom(x) intersect s)==0 then b==false elseif s == min(s)..max(s) then (b -> min(s) <= x) /\ (b -> x <= max(s)) else if card(dom(x))<=nMZN__UnaryLenMax_setInReif then %% PARAM TODO let { array[int] of var int: p = eq_encode(x); } in sum(i in s intersect dom(x))(p[i]) >= bool2int(b) else bool2int(b) <= fVarInBigSetOfInt(x, s) endif endif ) endif; function var 0..1: fVarInBigSetOfInt(var int: x, set of int: s) = let { array[int] of int: sL = [ e | e in s where not (e - 1 in s) ]; array[int] of int: sR = [ e | e in s where not (e + 1 in s) ]; constraint assert(length(sR)==length(sL), "N of lb and ub of sub-intervals of a set should be equal"); } in sum(i in index_set(sL)) (bool2int(x>=sL[i] /\ x<=sR[i])); %% use indicators %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% OTHER SET STUFF COMING FROM nosets.mzn %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% annotation bool_search(array[$X] of var bool: x, ann:a1, ann:a2, ann:a3) = let { array[int] of var bool: xx = array1d(x) } in int_search([bool2int(xx[i]) | i in index_set(xx)],a1,a2,a3); annotation warm_start( array[int] of var bool: x, array[int] of bool: v ) = warm_start( [ bool2int(x[i]) | i in index_set(x) ], [ bool2int(v[i]) | i in index_set(v) ] ); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% DOMAIN POSTPROCESSING BUILT-INS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Single variable: x = d <-> x_eq_d[d] predicate equality_encoding__POST(var int: x, array[int] of var int: x_eq_d); %%%%%%% var int: b: bool2int is a reverse_map, not passed to .fzn predicate set_in__POST(var int: x, set of int: s__); predicate set_in_reif__POST(var int: x, set of int: s__, var int: b); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% LOGICAL CONSTRAINTS TO THE SOLVER %%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%% var int: b: bool2int is a reverse_map, not passed to .fzn => REPEAT TESTS. TODO predicate int_lin_eq_reif__IND(array[int] of int: c, array[int] of var int: x, int: d, var int: b); predicate int_lin_le_reif__IND(array[int] of int: c, array[int] of var int: x, int: d, var int: b); predicate int_lin_ne__IND(array[int] of int: c, array[int] of var int: x, int: d); predicate aux_int_le_zero_if_0__IND(var int: x, var int: b); predicate float_lin_le_reif__IND(array[int] of float: c, array[int] of var float: x, float: d, var int: b); predicate aux_float_eq_if_1__IND(var float: x, var float: y, var int: b); predicate aux_float_le_zero_if_0__IND(var float: x, var int: b); predicate array_int_minimum__IND(var int: m, array[int] of var int: x); predicate array_int_maximum__IND(var int: m, array[int] of var int: x); predicate array_float_minimum__IND(var float: m, array[int] of var float: x); predicate array_float_maximum__IND(var float: m, array[int] of var float: x); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% XBZ cut generator, currently CPLEX only %%%%%%%%%%%%%%%%%%%%%%%%%% predicate array_var_float_element__XBZ_lb__cutgen(array[int] of var float: x, array[int] of var int: b, var float: z); libminizinc-2.4.2/share/minizinc/linear/redefs_bool_imp.mzn000066400000000000000000000044251360574160400241130ustar00rootroot00000000000000include "redefs_lin_halfreifs.mzn"; % SIMPLE BOOLEAN LOGIC % TODO: why not check "is_fixed(r)" everywhere?? predicate bool_eq_imp(var bool: p, var bool: q, var bool: r) = if is_fixed(r) then if fix(r) then p = q else true endif else let { var int: x = bool2int(p), var int: y = bool2int(q), var int: z = bool2int(r) } in x + z <= y + 1 /\ y + z <= x + 1 endif; predicate bool_ne_imp(var bool: p, var bool: q, var bool: r) = bool_xor_imp(p, q, r); predicate bool_le_imp(var bool: p, var bool: q, var bool: r) = let { var int: x = bool2int(p), var int: y = bool2int(q), var int: z = bool2int(r), } in 1 - x + y >= z; predicate bool_lt_imp(var bool: p, var bool: q, var bool: r) = bool_and_imp(not p, q, r); predicate bool_or_imp(var bool: p, var bool: q, var bool: r) = array_bool_or_imp([p,q], r); predicate bool_and_imp(var bool: p, var bool: q, var bool: r) = array_bool_and_imp([p,q],r); predicate bool_xor_imp(var bool: p, var bool: q, var bool: r) = let { var int: x = bool2int(p), var int: y = bool2int(q), var int: z = bool2int(r), } in x + y >= z /\ x + y + z <= 2; % BOOLEAN ARRAY OPERATIONS predicate array_bool_or_imp(array[int] of var bool: a, var bool: b) = if forall( i in index_set( a ) )( is_fixed(a[i]) /\ not fix(a[i]) ) then not b elseif exists( i in index_set( a ) )( is_fixed(a[i]) /\ fix(a[i]) ) then true else let { array[index_set(a)] of var bool: a1; var int: x = bool2int(b), } in forall(i in index_set(a)) (a1[i] -> a[i]) /\ sum(a1) = x endif; predicate array_bool_and_imp(array[int] of var bool: a, var bool: b) = if is_fixed(b) then if fix(b) then forall(i in index_set(a))( a[i] ) else true endif elseif forall( i in index_set( a ) )( is_fixed(a[i]) /\ fix(a[i]) ) then true else let { var int: x = bool2int(b), array[index_set(a)] of var int: c = array1d(index_set(a), [ bool2int(a[i] ) | i in index_set(a) ]) } in forall(i in index_set(c)) ( c[i] >= x ) endif; %% No var int d, sorry TODO: why not??? predicate bool_lin_eq_imp(array[int] of int: c, array[int] of var bool: x, int: d, var bool: b) = aux_int_eq_if_1(sum(i in index_set(x))( c[i]*bool2int(x[i]) ), d, bool2int(b)); libminizinc-2.4.2/share/minizinc/linear/redefs_bool_reifs.mzn000066400000000000000000000130441360574160400244330ustar00rootroot00000000000000/* % FlatZinc built-in redefinitions for linear solvers. % % AUTHORS % Sebastian Brand % Gleb Belov */ %-----------------------------------------------------------------------------% % % Logic operations % Use indicators for reifs (CPLEX)? Seems weak. % %-----------------------------------------------------------------------------% predicate bool_not(var bool: p, var bool: q) = bool2int(p) + bool2int(q) = 1; predicate bool_and(var bool: p, var bool: q, var bool: r) = % my_trace(" bool_and: \(p) /\\ \(q) <-> \(r) \n") /\ if false then int_lin_le_reif__IND( [-1, -1], [p, q], -2, r) else array_bool_and( [p, q], r ) % bool_and__INT(bool2int(p), bool2int(q), bool2int(r)) endif; predicate bool_and__INT(var int: x, var int: y, var int: z) = x + y <= z + 1 /\ %% x + y >= z * 2; % weak x >= z /\ y >= z; % strong predicate bool_or(var bool: p, var bool: q, var bool: r) = if false then int_lin_le_reif__IND( [-1, -1], [p, q], -1, r) elseif true then array_bool_or( [p, q], r ) else let { var int: x = bool2int(p), var int: y = bool2int(q), var int: z = bool2int(r) } in x + y >= z /\ % x + y <= z * 2; % weak x <= z /\ y <= z % strong endif; predicate bool_xor(var bool: p, var bool: q) = 1==p+q; predicate bool_xor(var bool: p, var bool: q, var bool: r) = if false then % int_lin_eq_reif__IND( [1, 1], [p, q], 1, r) /\ true else let { var int: x = bool2int(p), var int: y = bool2int(q), var int: z = bool2int(r) } in x <= y + z /\ y <= x + z /\ z <= x + y /\ x + y + z <= 2 endif; predicate bool_eq_reif(var bool: p, var bool: q, var bool: r) = %% trace(" bool_eq_reif: \(p), \(q), \(r) \n") /\ if is_fixed(r) then % frequent case if fix(r) = true then p = q else bool_not(p,q) endif elseif is_fixed(q) then if fix(q) = true then p = r else bool_not(p,r) endif elseif is_fixed(p) then if fix(p) = true then q = r else bool_not(q,r) endif elseif false then % int_lin_eq_reif__IND( [1, -1], [p, q], 0, r) /\ true else let { var int: x = bool2int(p), var int: y = bool2int(q), var int: z = bool2int(r) } in x + y <= z + 1 /\ x + z <= y + 1 /\ y + z <= x + 1 /\ x + y + z >= 1 endif; predicate bool_ne_reif(var bool: p, var bool: q, var bool: r) = bool_xor(p, q, r); predicate bool_le(var bool: p, var bool: q) = let { var int: x = bool2int(p), var int: y = bool2int(q) } in x <= y; predicate bool_le_reif(var bool: p, var bool: q, var bool: r) = if false then % int_lin_le_reif__IND( [1, -1], [p, q], 0, r) /\ true else let { var int: x = bool2int(p), var int: y = bool2int(q), var int: z = bool2int(r) } in 1 - x + y >= z /\ %% /\ 1 - x + y <= z * 2 not needed 1 - x <= z /\ y <= z % strong endif; predicate bool_lt(var bool: p, var bool: q) = not p /\ q; predicate bool_lt_reif(var bool: p, var bool: q, var bool: r) = (not p /\ q) <-> r; %-----------------------------------------------------------------------------% %% Reified disjunction predicate array_bool_or(array[int] of var bool: a, var bool: b) = if exists( i in index_set( a ) )( is_fixed(a[i]) /\ fix(a[i]) ) then b elseif is_fixed(b) then % frequent case if fix(b) = true then sum(i in index_set(a))( bool2int(a[i]) ) >= 1 %% >=1 seems better for MIPDomains... 5.4.19 else forall(i in index_set(a))( not a[i] ) endif else let { var int: x = bool2int(b), array[1..length(a)] of var int: c = [ bool2int(a[i]) | i in index_set(a) ] } in sum(c) >= x /\ % sum(c) <= x * length(a) % weak forall (i in index_set(a)) (x >= c[i]) % strong endif; %% Reified conjunction predicate array_bool_and(array[int] of var bool: a, var bool: b) = if exists( i in index_set( a ) )( is_fixed(a[i]) /\ not fix(a[i]) ) then not b elseif is_fixed(b) then % frequent case if fix(b) = false then sum(i in index_set(a))( bool2int(a[i]) ) <= length(a)-1 else forall(i in index_set(a))( a[i] ) endif else let { var int: x = bool2int(b), array[1..length(a)] of var int: c = [ bool2int(a[i]) | i in index_set(a) ] } in length(a) - sum(c) >= 1 - x /\ % length(a) - sum(c) <= (1 - x) * length(a); % weak forall (i in index_set(a)) (x <= c[i]) % strong endif; % predicate array_bool_xor(array[int] of var bool: a) = .. sum(a) is odd .. predicate array_bool_xor(array[int] of var bool: a) = let { var 0..(length(a)-1) div 2: m, var 1..((length(a)-1) div 2)*2+1: ss = sum(i in index_set(a))( bool2int(a[i]) ) } in ss == 1 + 2 * m; predicate bool_clause(array[int] of var bool: p, array[int] of var bool: n) = sum(i in index_set(p))( bool2int(p[i]) ) - sum(i in index_set(n))( bool2int(n[i]) ) + length(n) >= 1; predicate bool_lin_eq(array[int] of int: c, array[int] of var bool: x, var int: d) :: promise_total = sum(i in index_set(x))( c[i]*bool2int(x[i]) ) == d; predicate bool_lin_eq_reif(array[int] of int: c, array[int] of var bool: x, int: d, var bool: b) = %% No var int d, sorry aux_int_eq_iff_1(sum(i in index_set(x))( c[i]*bool2int(x[i]) ), d, bool2int(b)); libminizinc-2.4.2/share/minizinc/linear/redefs_lin_halfreifs.mzn000066400000000000000000000207421360574160400251200ustar00rootroot00000000000000/* % FlatZinc built-in redefinitions for linear solvers. % % AUTHORS % Sebastian Brand % Gleb Belov */ %-----------------------------------------------------------------------------% % Auxiliary: indicator constraints % p -> x # 0 where p is a 0/1 variable and # is a comparison % Base cases %% used e.g. in element predicate aux_float_eq_if_1(var float: x, var float: y, var int: p) = if is_fixed(p) then if 1==fix(p) then x==y else true endif elseif is_fixed(x) /\ is_fixed(y) then %%% Needed to avoid constant domain var if fix(x)!=fix(y) then p==0 else true endif elseif is_fixed(x-y) then %%% Hypothetically possible to land here if 0.0!=fix(x-y) then p==0 else true endif elseif fPostprocessDomains /\ fPostproDom_AUX /\ fPostproDom_DIFF then aux_float_eq_zero_if_1__POST(x - y, p, p) elseif fMZN__UseIndicators then aux_float_eq_if_1__IND(x, y, p) else aux_float_le_if_1(x, y, p) /\ aux_float_ge_if_1(x, y, p) endif; predicate aux_int_eq_if_1(var int: x, var int: y, var int: p) = if is_fixed(p) then if fix(p) = 1 then (x = y) else true endif elseif is_fixed(x) /\ is_fixed(y) then if fix(x) != fix(y) then (p = 0) else true endif % elseif is_fixed(x-y) then % TODO: Necessary for integers?? % if 0.0!=fix(x-y) then p==0 else true endif % elseif fPostprocessDomains /\ fPostproDom_AUX /\ fPostproDom_DIFF then % % TODO MIPDomains % elseif fMZN__UseIndicators then % TODO: Necessary for integers?? % aux_float_eq_if_1__IND(x, y, p) else aux_int_le_if_1(x, y, p) /\ aux_int_ge_if_1(x, y, p) endif; predicate aux_float_ne_if_1(var float: x, var float: y, var int: p) = if is_fixed(p) then if fix(p) = 1 then (x != y) else true endif elseif is_fixed(x) /\ is_fixed(y) then %%% Needed to avoid constant domain var if (fix(x) = fix(y)) then (p = 0) else true endif elseif is_fixed(x-y) then %%% Hypothetically possible to land here if (0.0 = fix(x-y)) then (p = 0) else true endif % TODO: What is necessary for not equals? % elseif fPostprocessDomains /\ fPostproDom_AUX /\ fPostproDom_DIFF then % aux_float_ne_zero_if_1__POST(x - y, p, p) % elseif fMZN__UseIndicators then % aux_float_ne_if_1__IND(x, y, p) else let { array[1..2] of var bool: q } in ( q[1] -> (x < y) ) /\ ( q[2] -> (x > y) ) /\ (sum(q) = p) endif; predicate aux_int_ne_if_1(var int: x, var int: y, var int: p) = if is_fixed(p) then if fix(p) = 1 then (x != y) else true endif elseif is_fixed(x) /\ is_fixed(y) then if fix(x) = fix(y) then (p = 0) else true endif % elseif is_fixed(x-y) then % TODO: Necessary for integers?? % if 0.0!=fix(x-y) then p==0 else true endif % elseif fPostprocessDomains /\ fPostproDom_AUX /\ fPostproDom_DIFF then % % TODO MIPDomains % elseif fMZN__UseIndicators then % TODO: Necessary for integers?? % aux_float_eq_if_1__IND(x, y, p) else let { array[1..2] of var bool: q } in ( q[1] -> (x < y) ) /\ ( q[2] -> (x > y) ) /\ (sum(q) = p) endif; predicate aux_int_le_zero_if_0(var int: x, var int: p) = if is_fixed(p) then if 0==fix(p) then x<=0 else true endif %% 0==fix !! elseif lb(x)>0 then p==1 elseif not (0 in dom(x)) then let { constraint assert( ub(x) < infinity, "aux_int_le_zero_if_0: variable \(x)'s domain: dom(\(x)) = \(dom(x)), should have finite upper bound\n" ), set of int: sDomNeg = dom(x) intersect -infinity..-1, constraint assert( card( sDomNeg ) > 0, "Variable \(x): dom(\(x)) = \(dom(x)), but dom() intersect -inf..-1: \(sDomNeg)\n" ), } in aux_int_le_if_0( x, max( sDomNeg ), p ) elseif fPostprocessDomains /\ fPostproDom_AUX then aux_int_le_zero_if_1__POST(x, 1-p) elseif fMZN__UseIndicators then aux_int_le_zero_if_0__IND(x, p) else assert( ub(x)0.0 then p==1 elseif fPostprocessDomains /\ fPostproDom_AUX then aux_float_le_zero_if_1__POST(x, 1-p, 1-p) elseif fMZN__UseIndicators then aux_float_le_zero_if_0__IND(x, p) else x <= ub(x) * p endif; predicate aux_float_lt_zero_if_0(var float: x, var int: p) = assert( has_bounds(x), "Variable \(x) needs finite bounds for a big-M constraint" ) /\ if is_fixed(p) then if 0==fix(p) then x<0.0 else true endif elseif lb(x)>=0.0 then p==1 elseif fPostprocessDomains /\ fPostproDom_AUX then aux_float_lt_zero_if_1__POST(x, 1-p, 1-p, float_lt_EPS) elseif fMZN__UseIndicators then aux_float_le_zero_if_0__IND(x+float_lt_EPS, p) %% Here just absolute EPS, TODO else %% let { float: rho = float_lt_EPS_coef__ * max(abs(ub(x)), abs(lb(x))) } % same order of magnitude as ub(x) let { float: rho = float_lt_EPS } % absolute eps in %%% This one causes 2x- derivation of EPS: %% x < (ub(x) + rho) * p %%% Better? x <= (ub(x) + rho) * p - rho %%% This just uses absolute eps: %% x < (ub(x) + float_lt_EPS) * p endif; % Derived cases predicate aux_int_le_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y, p); predicate aux_int_ge_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x, p); predicate aux_int_le_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y, 1 - p); predicate aux_int_ge_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x, 1 - p); predicate aux_int_lt_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y + 1, p); predicate aux_int_gt_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x + 1, p); predicate aux_int_lt_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y + 1, 1 - p); predicate aux_int_gt_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x + 1, 1 - p); %% int: switching differences to float to avoid creating integer vars /* Used anywhere? predicate aux_int_le_if_0(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(x - y, p); predicate aux_int_ge_if_0(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(y - x, p); predicate aux_int_le_if_1(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(x - y, 1 - p); predicate aux_int_ge_if_1(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(y - x, 1 - p); predicate aux_int_lt_if_0(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(x - y + 1.0, p); predicate aux_int_gt_if_0(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(y - x + 1.0, p); predicate aux_int_lt_if_1(var float: x, float: y, var int: p) = aux_float_le_zero_if_0(x - y + 1.0, 1 - p); */ predicate aux_float_le_if_0(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(x - y, p); predicate aux_float_ge_if_0(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(y - x, p); predicate aux_float_le_if_1(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(x - y, 1 - p); predicate aux_float_ge_if_1(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(y - x, 1 - p); predicate aux_float_lt_if_0(var float: x, var float: y, var int: p) = aux_float_lt_zero_if_0(x - y, p); predicate aux_float_gt_if_0(var float: x, var float: y, var int: p) = aux_float_lt_zero_if_0(y - x, p); predicate aux_float_lt_if_1(var float: x, var float: y, var int: p) = aux_float_lt_zero_if_0(x - y, 1 - p); predicate aux_float_gt_if_1(var float: x, var float: y, var int: p) = aux_float_lt_zero_if_0(y - x, 1 - p); % -------------------------- Domains postpro --------------------------- %% To avoid looking if an original int var x-y exists and has eq_encode: %% Passing both int and float version of the indicator for flexibility: predicate aux_float_eq_zero_if_1__POST(var float: x, var int: pI, var float: p); predicate aux_int_le_zero_if_1__POST(var int: x, var int: p); predicate aux_float_le_zero_if_1__POST(var float: x, var int: pI, var float: p); predicate aux_float_lt_zero_if_1__POST(var float: x, var int: pI, var float: p, float: eps); libminizinc-2.4.2/share/minizinc/linear/redefs_lin_imp.mzn000066400000000000000000000172451360574160400237460ustar00rootroot00000000000000include "redefs_lin_halfreifs.mzn"; include "redefs_lin_reifs.mzn"; %% var, var predicate int_le_imp(var int: x, var int: y, var bool: b) = if is_fixed(b) then if fix(b) then x<=y else true endif elseif ub(x)<=lb(y) then true elseif lb(x)>ub(y) then (not b) % elseif fPostprocessDomains /\ fPostproDom_DIFF then % % TODO MIPDomains else aux_int_le_if_1(x, y, b) endif; %% var, var predicate int_lt_imp(var int: x, var int: y, var bool: b) = if is_fixed(x) then int_le_imp(x + 1, y, b) else int_le_imp(x, y - 1, b) endif; %% var, var predicate int_eq_imp(var int: x, var int: y, var bool: b) = if is_fixed(b) then if fix(b) then (x = y) else true endif elseif card( dom(x) intersect dom(y) ) > 0 then if is_fixed(x) then if is_fixed(y) then b -> (fix(x) = fix(y)) else int_eq_imp(y, fix(x), b) endif elseif is_fixed(y) then int_eq_imp(x, fix(y), b) % elseif fPostprocessDomains /\ fPostproDom_DIFF then % % TODO MIPDomains else aux_int_eq_if_1(x, y, b) endif else not b endif; %% var, const predicate int_eq_imp(var int: x, int: y, var bool: b) = if is_fixed(b) then if fix(b) then (x = y) else true endif elseif y in dom(x) then if is_fixed(x) then b -> (y = fix(x)) % elseif fPostprocessDomains then % % TODO MIPDomains else aux_int_eq_if_1(x, y, b) endif else not b endif; %% var, var predicate int_ne_imp(var int: x, var int: y, var bool: b) = if is_fixed(b) then if fix(b) then (x != y) else true endif elseif (ub(x) < lb(y)) \/ (lb(x) > ub(y)) then true else if is_fixed(x) then if is_fixed(y) then b -> (fix(x) != fix(y)) else int_ne_imp(y, fix(x), b) endif elseif is_fixed(y) then int_ne_imp(x, fix(y), b) % elseif fPostprocessDomains /\ fPostproDom_DIFF then % % TODO MIPDomains else aux_int_ne_if_1(x, y, b) endif endif; %% var, const predicate int_ne_imp(var int: x, int: y, var bool: b) = if is_fixed(b) then if fix(b) then (x != y) else true endif elseif (ub(x) < lb(y)) \/ (lb(x) > ub(y)) then true else if is_fixed(x) then b -> (y != fix(x)) % elseif fPostprocessDomains then % % TODO MIPDomains else aux_int_ne_if_1(x, y, b) endif endif; %-----------------------------------------------------------------------------% %% lin_expr, const predicate int_lin_le_imp(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = if (d = 0) /\ (length(c) = 2) /\ (abs(c[1]) = 1) /\ (c[1] = -1 * c[2]) then if (c[1] < 0) then int_le_imp(x[2], x[1], b) else int_le_imp(x[1], x[2], b) endif elseif fPostprocessDomains /\ fPostproDom_DIFF then int_le_imp(sum(i in index_set(x))(c[i] * x[i]), d, b) elseif fAvoidNI then aux_float_le_if_1(sum2float(c, x), d, b) else aux_int_le_if_1(sum(i in index_set(x))(c[i] * x[i]), d, b) endif; predicate int_lin_lt_imp(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = if true then abort("int_lin_lt_imp not supposed to be called") else int_lin_le_imp(c, x, d - 1, b) endif; %% lin_expr, const predicate int_lin_eq_imp(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = if (d = 0) /\ (length(c) = 2) /\ (abs(c[1]) = 1) /\ (c[1] = -1 * c[2]) then int_ne_imp(x[1], x[2], b) elseif fPostprocessDomains /\ fPostproDom_DIFF then int_eq_imp(sum(i in index_set(x))(c[i] * x[i]), d, b) elseif fAvoidNI then aux_float_eq_if_1(sum2float(c, x), d, b) else aux_int_eq_if_1(sum(i in index_set(x))(c[i] * x[i]), d, b) endif; %% lin_expr, const predicate int_lin_ne_imp(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = if (d = 0) /\ (length(c) = 2) /\ (abs(c[1]) = 1) /\ (c[1] = -1 * c[2]) then int_ne_imp(x[1], x[2], b) elseif fPostprocessDomains /\ fPostproDom_DIFF then int_ne_imp(sum(i in index_set(x))(c[i] * x[i]), d, b) elseif fAvoidNI then aux_float_ne_if_1(sum2float(c, x), d, b) else aux_int_ne_if_1(sum(i in index_set(x))(c[i] * x[i]), d, b) endif; %-----------------------------------------------------------------------------% %% var float, var float predicate float_le_imp(var float: x, var float: y, var bool: b) = if is_fixed(b) then if fix(b) then x <= y else true endif elseif ub(x) <= lb(y) then true elseif lb(x) > ub(y) then (not b) % elseif fPostprocessDomains /\ fPostproDom_DIFF then % % TODO MIPDomains else aux_float_le_if_1(x, y, b) endif; %% var float, var float predicate float_lt_imp(var float: x, var float: y, var bool: b) = if is_fixed(b) then if fix(b) then (x < y) else true endif % elseif fPostprocessDomains /\ fPostproDom_DIFF then % % TODO MIPDomains else aux_float_lt_if_1(x, y, b) endif; %% var float, var float predicate float_eq_imp(var float: x, var float: y, var bool: b) = if is_fixed(b) then if fix(b) then (x = y) else true endif elseif (ub(x) < lb(y)) \/ (lb(x) > ub(y)) then not b elseif is_fixed(x) /\ is_fixed(y) then b -> (fix(x) == fix(y)) % elseif fPostprocessDomains /\ fPostproDom_DIFF then % % TODO MIPDomains else aux_float_eq_if_1(x, y, b) endif; %% var float, var float predicate float_ne_imp(var float: x, var float: y, var bool: b) = if is_fixed(b) then if fix(b) then (x != y) else true endif elseif (ub(x) < lb(y)) \/ (lb(x) > ub(y)) then true elseif is_fixed(x) /\ is_fixed(y) then b -> (fix(x) != fix(y)) % elseif fPostprocessDomains /\ fPostproDom_DIFF then % % TODO MIPDomains else aux_float_ne_if_1(x, y, b) endif; %-----------------------------------------------------------------------------% predicate float_lin_eq_imp(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = if (d = 0.0) /\ (length(c) = 2) /\ (abs(c[1]) = 1.0) /\ (c[1] = -1.0 * c[2]) then float_eq_imp(x[1], x[2], b) elseif fPostprocessDomains /\ fPostproDom_DIFF then float_eq_imp(sum(i in index_set(x))(c[i] * x[i]), d, b) else aux_float_eq_if_1(sum(i in index_set(x))(c[i] * x[i]), d, b) endif; predicate float_lin_ne_imp(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = if (d = 0.0) /\ (length(c) = 2) /\ (abs(c[1]) = 1.0) /\ (c[1] = -1.0 * c[2]) then float_ne_imp(x[1], x[2], b) elseif fPostprocessDomains /\ fPostproDom_DIFF then float_ne_imp(sum(i in index_set(x))(c[i] * x[i]), d, not b) else aux_float_ne_if_1(sum(i in index_set(x))(c[i] * x[i]), d, b) endif; predicate float_lin_le_imp(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = if (d = 0.0) /\ (length(c) = 2) /\ (abs(c[1]) = 1.0) /\ (c[1] = -1.0 * c[2]) then if (c[1] < 0.0) then float_le_imp(x[2], x[1], b) else float_le_imp(x[1], x[2], b) endif elseif fPostprocessDomains /\ fPostproDom_DIFF then float_le_imp(sum(i in index_set(x))(c[i] * x[i]), d, b) else aux_float_le_if_1(sum(i in index_set(x))(c[i] * x[i]), d, b) endif; predicate float_lin_lt_imp(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = if (d = 0.0) /\ (length(c) = 2) /\ (abs(c[1]) = 1.0) /\ (c[1] = -1.0 * c[2]) then if (c[1] < 0.0) then float_lt_imp(x[2], x[1], b) else float_lt_imp(x[1], x[2], b) endif elseif fPostprocessDomains /\ fPostproDom_DIFF then float_lt_imp(sum(i in index_set(x))(c[i] * x[i]), d, b) else aux_float_lt_if_1(sum(i in index_set(x))(c[i] * x[i]), d, b) endif; libminizinc-2.4.2/share/minizinc/linear/redefs_lin_reifs.mzn000066400000000000000000000364471360574160400242760ustar00rootroot00000000000000/* % FlatZinc built-in redefinitions for linear solvers. % % AUTHORS % Sebastian Brand % Gleb Belov */ %-----------------------------------------------------------------------------% % % Linear equations and inequations % TODO Use indicators for (half)reifs. % Otherwise and more using unary encoding for reasonable domains % %-----------------------------------------------------------------------------% % Domains: reduce all to aux_ stuff? %% never use Concert's reif feature %% var, var predicate int_le_reif(var int: x, var int: y, var bool: b) = %% trace(" int_le_reif VV: \(x), \(y), \(b) \n") /\ if is_fixed(b) then if true==fix(b) then x<=y else x>y endif elseif ub(x)<=lb(y) then b==true elseif lb(x)>ub(y) then b==false elseif fPostprocessDomains /\ fPostproDom_DIFF then int_le_reif__POST(x-y, 0, b) else int_le_reif__NOPOST(x, y, b) endif ; %% const, var predicate int_le_reif(int: x, var int: y, var bool: b) = %% trace(" int_le_reif CV: \(x), \(y), \(b) \n") /\ if is_fixed(b) then if true==fix(b) then x<=y else x>y endif elseif ub(x)<=lb(y) then b==true elseif lb(x)>ub(y) then b==false elseif not (x in dom(y)) then %% dom(y) has holes let { set of int: sDom2 = dom(y) intersect x+1..infinity, constraint assert( card( sDom2 ) > 0, "Variable: dom(\(y)) = \(dom(y)), but dom() intersect \(x)..inf: \(sDom2)\n" ), } in b <-> min( sDom2 ) <= y elseif fPostprocessDomains then int_ge_reif__POST(y, x, b) else int_le_reif(-y, -x, b) endif ; %% var, const predicate int_le_reif(var int: x, int: y, var bool: b) = %% trace(" int_le_reif VC: \(x), \(y), \(b) \n") /\ if is_fixed(b) then if true==fix(b) then x<=y else x>y endif elseif ub(x)<=lb(y) then b==true elseif lb(x)>ub(y) then b==false elseif not (y in dom(x)) then %% dom(x) has holes let { set of int: sDom2 = dom(x) intersect -infinity..y-1, constraint assert( card( sDom2 ) > 0, "Variable: dom(\(x)) = \(dom(x)), but dom() intersect -inf..\(y): \(sDom2)\n" ), } in b <-> x <= max( sDom2 ) else if fPostprocessDomains then int_le_reif__POST(x, y, b) else int_le_reif__NOPOST(x, y, b) endif endif ; %% var int, var int predicate int_le_reif__NOPOST(var int: x, var int: y, var bool: b) = aux_int_le_if_1(x, y, b) /\ %% This can call POSTs... TODO aux_int_gt_if_0(x, y, b) ; %% var, var predicate int_lt_reif(var int: x, var int: y, var bool: b) = %% int_le_reif(x-y, -1, b); %% This would produce a new variable x-y and possibly POST it %% but it looks like differences should not be if is_fixed( x ) then int_le_reif(x+1, y, b) else int_le_reif(x, y-1, b) endif; %% var, var predicate int_ne(var int: x, var int: y) = if fPostproDom_DIFF then int_ne(x-y, 0) else int_ne__SIMPLE(x-y, 0) endif; %% var, const predicate int_ne(var int: x, int: y) = if y in dom(x) then if y==ub(x) then x <= y-1 elseif y==lb(x) then x >= y+1 elseif fPostprocessDomains then int_ne__POST(x, y) elseif card(dom(x))y) endif; %% var, var predicate int_eq_reif(var int: x, var int: y, var bool: b) = %% trace(" int_eq_reif VV: \(x), \(y), \(b) \n") /\ if is_fixed(b) then if fix(b) then x==y else x!=y endif elseif card(dom(x) intersect dom(y))>0 then if is_fixed(x) then if is_fixed(y) then b <-> fix(x)==fix(y) else int_eq_reif(y, fix(x), b) endif elseif is_fixed(y) then int_eq_reif(x, fix(y), b) elseif fPostprocessDomains /\ fPostproDom_DIFF then int_eq_reif(x-y, 0, b) else aux_int_eq_iff_1(x, y, b) endif else not b endif; %% var, const predicate int_eq_reif(var int: x, int: y, var bool: b) = %% trace(" int_eq_reif VC: \(x), \(y), \(b) \n") /\ if is_fixed(b) then if fix(b) then x==y else x!=y endif elseif y in dom(x) then if is_fixed(x) then b <-> y==fix(x) elseif card(dom(x))==2 then x == max(dom(x) diff {y}) + b*(y - max(dom(x) diff {y})) %% This should directly connect b to var 0..1: x elseif fPostprocessDomains then int_eq_reif__POST(x, y, b) %%% THIS seems pretty complex, especially for binaries, and does not connect to eq_encoding (/ MIPD?) %% elseif y==lb(x) then %% int_lt_reif(y, x, not b) %% elseif y==ub(x) then %% int_lt_reif(x, y, not b) elseif card(dom(x))y endif elseif false then float_lin_le_reif__IND( [1.0, -1.0], [x, y], 0.0, b) elseif ub(x) <= y then b == true elseif lb(x) > y then b == false elseif fPostprocessDomains then float_le_reif__POST(x, y, b, float_lt_EPS) else float_le_reif__NOPOST(x, y, b) endif; %% const, var float predicate float_le_reif(float: x, var float: y, var bool: b) = if is_fixed(b) then if true==fix(b) then x<=y else x>y endif elseif false then float_lin_le_reif__IND( [1.0, -1.0], [x, y], 0.0, b) elseif ub(x) <= lb(y) then b == true elseif lb(x) > ub(y) then b == false elseif fPostprocessDomains then float_ge_reif__POST(y, x, b, float_lt_EPS) else float_le_reif(-y, -x, b) endif; %% var float, var float predicate float_le_reif(var float: x, var float: y, var bool: b) = if is_fixed(b) then if true==fix(b) then x<=y else x>y endif elseif ub(x)<=lb(y) then b==true elseif lb(x)>ub(y) then b==false elseif fPostprocessDomains /\ fPostproDom_DIFF then float_le_reif(x-y, 0.0, b) else float_le_reif__NOPOST(x-y, 0, b) endif ; %% var float, var float predicate float_le_reif__NOPOST(var float: x, var float: y, var bool: b) = aux_float_le_if_1(x, y, (b)) /\ %% Can call __POSTs TODO aux_float_gt_if_0(x, y, (b)) ; %% TODO predicate float_lt_reif(var float: x, var float: y, var bool: b) = %% Actually = float_le_reif(x, y-eps, b). if is_fixed(b) then if true==fix(b) then x=y endif elseif fPostprocessDomains /\ fPostproDom_DIFF then aux_float_lt_zero_iff_1__POST(x - y, b, float_lt_EPS) else aux_float_lt_if_1(x, y, (b)) /\ aux_float_ge_if_0(x, y, (b)) endif; %% var, const predicate float_ne(var float: x, float: y) = if fPostprocessDomains then float_ne__POST(x, y, float_lt_EPS) else float_ne__SIMPLE(x, y) endif; predicate float_ne__SIMPLE(var float: x, var float: y) = if true then let { var 0..1: p } in aux_float_lt_if_1(x, y, (p)) /\ aux_float_gt_if_0(x, y, (p)) else %TODO: Why is this not half-reified? 1 == (x>y) + (xub(y) then b == false elseif is_fixed(x) /\ is_fixed(y) then b == (fix(x) == fix(y)) elseif fPostprocessDomains /\ fPostproDom_DIFF then float_eq_reif__POST(x-y, 0, b, float_lt_EPS) else aux_float_eq_iff_1(x, y, (bool2int(b))) endif; predicate float_ne_reif(var float: x, var float: y, var bool: b) = float_eq_reif(x, y, not (b)); %-----------------------------------------------------------------------------% predicate float_lin_eq_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = if fPostprocessDomains /\ fPostproDom_DIFF then float_eq_reif(sum(i in index_set(x))( c[i]*x[i] ), d, b) else aux_float_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, b) endif; predicate float_lin_ne_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = if fPostprocessDomains /\ fPostproDom_DIFF then float_ne_reif(sum(i in index_set(x))( c[i]*x[i] ), d, not b) else aux_float_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, not b) endif; predicate float_lin_le_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = if fPostprocessDomains /\ fPostproDom_DIFF then float_le_reif(sum(i in index_set(x))( c[i]*x[i] ), d, b) else float_le_reif__NOPOST(sum(i in index_set(x))( c[i]*x[i] ), d, b) endif; predicate float_lin_lt_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = float_lt_reif(sum(i in index_set(x))( c[i]*x[i] ), d, b); %-----------------------------------------------------------------------------% % Auxiliary: equality reified onto a 0/1 variable predicate aux_int_eq_iff_1(var int: x, var int: y, var int: p) = if is_fixed(p) then if 1==fix(p) then x==y else x!=y endif elseif fPostprocessDomains /\ fPostproDom_DIFF then abort(" aux_int_eq_iff_1 should not be used with full domain postprocessing") elseif false then true elseif fAuxIntEqOLD00 then let { array[1..2] of var 0..1: q } in aux_int_le_if_1(x, y, p) /\ aux_int_ge_if_1(x, y, p) /\ aux_int_lt_if_0(x, y, q[1]) /\ aux_int_gt_if_0(x, y, q[2]) /\ sum(q) == p + 1 else %% redundant p == (x<=y /\ y<=x) /\ 1+p == (x<=y) + (y<=x) endif; predicate aux_int_eq_iff_1__float(var float: x, float: y, var int: p) = if fAuxIntEqOLD00 then assert( false, "Don't use aux_int_eq_iff_1__float" ) /* let { array[1..2] of var 0..1: q } in aux_int_le_if_1(x, y, p) /\ aux_int_ge_if_1(x, y, p) /\ aux_int_lt_if_0(x, y, q[1]) /\ aux_int_gt_if_0(x, y, q[2]) /\ sum(q) == p + 1 */ else assert( false, "Don't use aux_int_eq_iff_1__float with fAuxIntEqOLD00" ) endif; % Alternative 2 predicate aux_int_eq_iff_1__WEAK1(var int: x, var int: y, var int: p) = let { array[1..2] of var 0..1: q_458 } in aux_int_lt_if_0(x - p, y, q_458[1]) /\ aux_int_gt_if_0(x + p, y, q_458[2]) /\ sum(q_458) <= 2 - 2*p /\ sum(q_458) <= 1 + p; % Alternative 1 predicate alt_1_aux_int_eq_iff_1(var int: x, var int: y, var int: p) = let { array[1..2] of var 0..1: q } in aux_int_lt_if_0(x - p, y, q[1]) /\ aux_int_gt_if_0(x + p, y, q[2]) /\ q[1] <= 1 - p /\ q[2] <= 1 - p /\ sum(q) <= 1 + p; predicate aux_float_eq_iff_1(var float: x, var float: y, var int: p) = if is_fixed(p) then if 1==fix(p) then x==y else x!=y endif elseif fPostprocessDomains /\ fPostproDom_DIFF then abort(" aux_float_eq_iff_1 should not be used with full domain postprocessing") elseif fAuxFloatEqOLD00 then let { array[1..2] of var 0..1: q } in aux_float_le_if_1(x, y, p) /\ aux_float_ge_if_1(x, y, p) /\ aux_float_lt_if_0(x, y, (q[1])) /\ aux_float_gt_if_0(x, y, (q[2])) /\ sum(i in 1..2)((q[i])) == 1 + p else %% redundant p == (x<=y /\ y<=x) /\ 1+p == (x<=y) + (y<=x) endif; % ----------------------------- Domains postpro --------------------------- %%%%%%%%%%%%%%%%%% predicate int_le_reif__POST(var int: x, var int: y, var int: b); %%%%%%%%%%%%%%%%%% predicate int_le_reif__POST(int: x, var int: y, var int: b); %%%%%%% var int: b: bool2int is a reverse_map, not passed to .fzn %% var, const predicate int_le_reif__POST(var int: x, int: y, var int: b); %% var, const predicate int_ge_reif__POST(var int: x, int: y, var int: b); %% var, const predicate int_eq_reif__POST(var int: x, int: y, var int: b); %% var, const predicate int_ne__POST(var int: x, int: y); %%%%%%%%%%%%%%%%%% predicate float_le_reif__POST(var float: x, var float: y, var int: b); %%%%%%%%%%%%%%%%%% predicate float_le_reif__POST(float: x, var float: y, var int: b); %% var, const predicate float_le_reif__POST(var float: x, float: y, var int: b, float: epsRel); %% var, const predicate float_ge_reif__POST(var float: x, float: y, var int: b, float: epsRel); %% var, var predicate aux_float_lt_zero_iff_1__POST(var float: x, var int: b, float: epsRel); %% var, const predicate float_eq_reif__POST(var float: x, float: y, var int: b, float: epsRel); %% var, const predicate float_ne__POST(var float: x, float: y, float: epsRel); libminizinc-2.4.2/share/minizinc/linear/subcircuit_wDummy.mzn000066400000000000000000000057321360574160400245030ustar00rootroot00000000000000/* Linearized version * Uses a predicate which constructs a subcircuit which always includes an extra dummy vertex * Is worse than the just slightly adapted standard variant... */ include "alldifferent.mzn"; /** @group globals Constrains the elements of \a x to define a subcircuit where \a x[\p i] = \p j means that \p j is the successor of \p i and \a x[\p i] = \p i means that \p i is not in the circuit. */ %% Linear version predicate subcircuit(array[int] of var int: x) = let { set of int: S = index_set(x), int: l = min(S), int: u = max(S), int: n = card(S), constraint forall(i in S)(x[i] in l..u), array[l..u+1] of var l..u+1: xx, constraint forall(i in S)(xx[i] in dom(x[i]) union {u+1}), } in alldifferent(x) /\ subcircuit_wDummy(xx) /\ forall( i in S, j in dom(x[i]) )( %% also when i==j? eq_encode(x[i])[j] >= 2*eq_encode(xx[i])[j] + eq_encode(xx[i])[u+1] + eq_encode(xx[u+1])[j] - 1 %% -1 /\ eq_encode(x[i])[j] >= eq_encode(xx[i])[j] /\ eq_encode(x[i])[j] <= eq_encode(xx[i])[j] + eq_encode(xx[i])[u+1] /\ eq_encode(x[i])[j] <= eq_encode(xx[i])[j] + eq_encode(xx[u+1])[j] ) /\ forall( i in S )( eq_encode(x[i])[i] == eq_encode(xx[i])[i] ) ; %% Should include at least 2 nodes if >0? %% xx[n] is dummy predicate subcircuit_wDummy(array[int] of var int: x) = let { set of int: S = index_set(x), int: l = min(S), int: u = max(S), int: n = card(S), set of int: S__ = S diff {u}, %% the real nodes array[S__] of var 2..n: order, %% constraint order[n]==1, %% fix the dummy %% var bool: empty = (firstin == u+1), no, break 2-cycles with dummy } in alldifferent(x) /\ % NO alldifferent(order) /\ %%% MTZ model. Note that INTEGER order vars seem better!: forall( i in S__, j in dom(x[i]) where i!=j /\ j!=u )( order[i] - order[j] + (n-1)*eq_encode(x[i])[j] % + (n-3)*bool2int(x[j]==i) %% the Desrochers & Laporte '91 term % --- strangely enough it is much worse on vrp-s2-v2-c7_vrp-v2-c7_det_ADAPT_1_INVERSE.mzn! <= n-2 ) /\ %% Break 2-cycles with dummy: forall( i in S__ )( eq_encode(x[i])[u] + eq_encode(x[u])[i] <= 1 /\ %% Ensure dummy is in: if i in dom(x[i]) then eq_encode(x[i])[i] >= eq_encode(x[u])[u] else true endif ) /\ % Symmetry? Each node that is not in is numbered after the lastin node. forall(i in S) ( true % (not ins[i]) <-> (n == order[i]) ) ; predicate subcircuit_reif(array[int] of var int: x, var bool: b) = abort("Reified subcircuit/1 is not supported."); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/linear_old/000077500000000000000000000000001360574160400210665ustar00rootroot00000000000000libminizinc-2.4.2/share/minizinc/linear_old/all_different_int.mzn000066400000000000000000000013211360574160400252610ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % 'all_different' constrains an array of objects to be all different. % % Linear version: equality encoding; see e.g. [Refalo, CP 2000] % % For a given d in dom(x), at most one i with x_i = d can exist. %-----------------------------------------------------------------------------% include "domain_encodings.mzn"; predicate all_different_int(array[int] of var int: x) = let { array[int,int] of var 0..1: x_eq_d = eq_encode(x) } in ( forall(d in index_set_2of2(x_eq_d))( sum(i in index_set_1of2(x_eq_d))( x_eq_d[i,d] ) <= 1 ) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/linear_old/domain_encodings.mzn000066400000000000000000000041531360574160400251170ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Domain encodings %-----------------------------------------------------------------------------% % Linear equality encoding % Single variable: x = d <-> x_eq_d[d] predicate equality_encoding(var int: x, array[int] of var 0..1: x_eq_d) = x in index_set(x_eq_d) /\ sum(d in dom(x))( x_eq_d[d] ) = 1 /\ sum(d in dom(x))( d * x_eq_d[d] ) = x; % Array of variables: x[i] = d <-> x_eq_d[i,d] predicate equality_encoding(array[int] of var int: x, array[int, int] of var 0..1: x_eq_d) = forall(i in index_set(x))( x[i] in index_set_2of2(x_eq_d) /\ sum(d in index_set_2of2(x_eq_d))( x_eq_d[i,d] ) = 1 /\ sum(d in index_set_2of2(x_eq_d))( d * x_eq_d[i,d] ) = x[i] ); function var int: eq_new_var(var int: x, int: i) = if i in dom(x) then let { var 0..1: xi; } in xi else 0 endif; function array[int] of var 0..1: eq_encode(var int: x) ::promise_total = let { array[int] of var 0..1: y = array1d(lb(x)..ub(x),[eq_new_var(x,i) | i in lb(x)..ub(x)]); constraint equality_encoding(x,y); } in y; function array[int] of int: eq_encode(int: x) ::promise_total = array1d(lb(x)..ub(x),[ if i=x then 1 else 0 endif | i in lb(x)..ub(x)]); function array[int,int] of var int: eq_encode(array[int] of var int: x) ::promise_total = let { array[index_set(x),lb_array(x)..ub_array(x)] of var 0..1: y = array2d(index_set(x),lb_array(x)..ub_array(x), [ let { array[int] of var int: xi = eq_encode(x[i]) } in if j in index_set(xi) then xi[j] else 0 endif | i in index_set(x), j in lb_array(x)..ub_array(x)] ) } in y; function array[int,int] of int: eq_encode(array[int] of int: x) ::promise_total = array2d(index_set(x),lb_array(x)..ub_array(x),[ if j=x[i] then 1 else 0 endif | i in index_set(x), j in lb_array(x)..ub_array(x)]); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/linear_old/inverse.mzn000066400000000000000000000013241360574160400232670ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Constrains two arrays of int variables to represent inverse functions. % All the values in each array must be within the index set of the other array. % % Linear version. %-----------------------------------------------------------------------------% include "domain_encodings.mzn"; predicate inverse(array[int] of var int: f, array[int] of var int: g) = let { array[int,int] of var 0..1: map_f = eq_encode(f); array[int,int] of var 0..1: map_g = eq_encode(g); } in forall (i in index_set(f), j in index_set(g)) (map_f[i,j] = map_g[j,i]); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/linear_old/linear/000077500000000000000000000000001360574160400223405ustar00rootroot00000000000000libminizinc-2.4.2/share/minizinc/linear_old/linear/all_different_int.mzn000066400000000000000000000013211360574160400265330ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % 'all_different' constrains an array of objects to be all different. % % Linear version: equality encoding; see e.g. [Refalo, CP 2000] % % For a given d in dom(x), at most one i with x_i = d can exist. %-----------------------------------------------------------------------------% include "domain_encodings.mzn"; predicate all_different_int(array[int] of var int: x) = let { array[int,int] of var 0..1: x_eq_d = eq_encode(x) } in ( forall(d in index_set_2of2(x_eq_d))( sum(i in index_set_1of2(x_eq_d))( x_eq_d[i,d] ) <= 1 ) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/linear_old/linear/domain_encodings.mzn000066400000000000000000000041531360574160400263710ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Domain encodings %-----------------------------------------------------------------------------% % Linear equality encoding % Single variable: x = d <-> x_eq_d[d] predicate equality_encoding(var int: x, array[int] of var 0..1: x_eq_d) = x in index_set(x_eq_d) /\ sum(d in dom(x))( x_eq_d[d] ) = 1 /\ sum(d in dom(x))( d * x_eq_d[d] ) = x; % Array of variables: x[i] = d <-> x_eq_d[i,d] predicate equality_encoding(array[int] of var int: x, array[int, int] of var 0..1: x_eq_d) = forall(i in index_set(x))( x[i] in index_set_2of2(x_eq_d) /\ sum(d in index_set_2of2(x_eq_d))( x_eq_d[i,d] ) = 1 /\ sum(d in index_set_2of2(x_eq_d))( d * x_eq_d[i,d] ) = x[i] ); function var int: eq_new_var(var int: x, int: i) = if i in dom(x) then let { var 0..1: xi; } in xi else 0 endif; function array[int] of var 0..1: eq_encode(var int: x) ::promise_total = let { array[int] of var 0..1: y = array1d(lb(x)..ub(x),[eq_new_var(x,i) | i in lb(x)..ub(x)]); constraint equality_encoding(x,y); } in y; function array[int] of int: eq_encode(int: x) ::promise_total = array1d(lb(x)..ub(x),[ if i=x then 1 else 0 endif | i in lb(x)..ub(x)]); function array[int,int] of var int: eq_encode(array[int] of var int: x) ::promise_total = let { array[index_set(x),lb_array(x)..ub_array(x)] of var 0..1: y = array2d(index_set(x),lb_array(x)..ub_array(x), [ let { array[int] of var int: xi = eq_encode(x[i]) } in if j in index_set(xi) then xi[j] else 0 endif | i in index_set(x), j in lb_array(x)..ub_array(x)] ) } in y; function array[int,int] of int: eq_encode(array[int] of int: x) ::promise_total = array2d(index_set(x),lb_array(x)..ub_array(x),[ if j=x[i] then 1 else 0 endif | i in index_set(x), j in lb_array(x)..ub_array(x)]); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/linear_old/linear/inverse.mzn000066400000000000000000000013241360574160400245410ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Constrains two arrays of int variables to represent inverse functions. % All the values in each array must be within the index set of the other array. % % Linear version. %-----------------------------------------------------------------------------% include "domain_encodings.mzn"; predicate inverse(array[int] of var int: f, array[int] of var int: g) = let { array[int,int] of var 0..1: map_f = eq_encode(f); array[int,int] of var 0..1: map_g = eq_encode(g); } in forall (i in index_set(f), j in index_set(g)) (map_f[i,j] = map_g[j,i]); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/linear_old/linear/redefinitions-2.0.2.mzn000066400000000000000000000014711360574160400263700ustar00rootroot00000000000000% This file contains redefinitions of standard builtins for version 2.0.2 % that can be overridden by solvers. predicate symmetry_breaking_constraint(var bool: b) = b; predicate redundant_constraint(var bool: b) = b; %% Linearized element: just call without shifting predicate array_var_bool_element_nonshifted(var int: idx, array[int] of var bool: x, var bool: c) = array_var_bool_element(idx,x,c); predicate array_var_int_element_nonshifted(var int: idx, array[int] of var int: x, var int: c) = array_var_int_element(idx,x,c); predicate array_var_float_element_nonshifted(var int: idx, array[int] of var float: x, var float: c) = array_var_float_element(idx,x,c); predicate array_var_set_element_nonshifted(var int: idx, array[int] of var set of int: x, var set of int: c) = array_var_set_element(idx,x,c); libminizinc-2.4.2/share/minizinc/linear_old/linear/redefinitions-2.0.mzn000066400000000000000000000003561360574160400262310ustar00rootroot00000000000000predicate bool_clause_reif(array[int] of var bool: p, array[int] of var bool: n, var bool: c) = c = ( sum(i in index_set(p))( bool2int(p[i]) ) - sum(i in index_set(n))( bool2int(n[i]) ) + length(n) >= 1 ); libminizinc-2.4.2/share/minizinc/linear_old/linear/redefinitions.mzn000066400000000000000000000451121360574160400257330ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % FlatZinc built-in redefinitions for linear solvers. % % Sebastian Brand % Gleb Belov Corrected array_var_float_element and float_lin_lt_reif %-----------------------------------------------------------------------------% function var bool: reverse_map(var int: x) = (x==1); function bool: reverse_map(int: x) = (x==1); function var int: bool2int(var bool: x) :: promise_total = let { var 0..1: b2i; constraint (x = reverse_map(b2i)) ::is_reverse_map ; } in b2i; predicate bool_eq(var bool: x, var bool: y) = bool2int(x)==bool2int(y); %-----------------------------------------------------------------------------% % Strict inequality % % Uncomment the following redefinition for FlatZinc MIP solver interfaces that % do not support strict inequality. Note that it does not preserve equivalence % (some solutions of the original problem may become invalid). % predicate float_lt(var float: x, var float: y) = x + 1e-06 <= y; %-----------------------------------------------------------------------------% % % Logic operations % %-----------------------------------------------------------------------------% predicate bool_not(var bool: p, var bool: q) = let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q) } in x + y = 1; predicate bool_and(var bool: p, var bool: q, var bool: r) = let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q), var 0..1: z = bool2int(r) } in x + y <= z + 1 /\ x + y >= z * 2; % x >= z /\ y >= z; % alternative predicate bool_or(var bool: p, var bool: q, var bool: r) = let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q), var 0..1: z = bool2int(r) } in x + y >= z /\ x + y <= z * 2; % x <= z /\ y <= z; % alternative predicate bool_xor(var bool: p, var bool: q, var bool: r) = let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q), var 0..1: z = bool2int(r) } in x <= y + z /\ y <= x + z /\ z <= x + y /\ x + y + z <= 2; predicate bool_eq_reif(var bool: p, var bool: q, var bool: r) = if is_fixed(q) then % frequent case if fix(q) = true then p = r else bool_not(p,r) endif else let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q), var 0..1: z = bool2int(r) } in x + y <= z + 1 /\ x + z <= y + 1 /\ y + z <= x + 1 /\ x + y + z >= 1 endif; predicate bool_ne_reif(var bool: p, var bool: q, var bool: r) = bool_xor(p, q, r); predicate bool_le(var bool: p, var bool: q) = let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q) } in x <= y; predicate bool_le_reif(var bool: p, var bool: q, var bool: r) = let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q), var 0..1: z = bool2int(r) } in 1 - x + y >= z /\ 1 - x + y <= z * 2; % 1 - x <= z /\ y <= z; % alternative predicate bool_lt(var bool: p, var bool: q) = not p /\ q; predicate bool_lt_reif(var bool: p, var bool: q, var bool: r) = (not p /\ q) <-> r; %-----------------------------------------------------------------------------% predicate array_bool_or(array[int] of var bool: a, var bool: b) = if is_fixed(b) then % frequent case if fix(b) = true then sum(i in index_set(a))( bool2int(a[i]) ) >= 1 else forall(i in index_set(a))( not a[i] ) endif else let { var 0..1: x = bool2int(b), array[1..length(a)] of var 0..1: c = [ bool2int(a[i]) | i in index_set(a) ] } in sum(c) >= x /\ sum(c) <= x * length(a) endif; predicate array_bool_and(array[int] of var bool: a, var bool: b) = let { var 0..1: x = bool2int(b), array[1..length(a)] of var 0..1: c = [ bool2int(a[i]) | i in index_set(a) ] } in length(a) - sum(c) >= 1 - x /\ length(a) - sum(c) <= (1 - x) * length(a); predicate array_bool_xor(array[int] of var bool: a) = let { var 0..length(a): m } in sum(i in 1..length(a))( bool2int(a[i]) ) = 1 + 2 * m; predicate bool_clause(array[int] of var bool: p, array[int] of var bool: n) = sum(i in index_set(p))( bool2int(p[i]) ) - sum(i in index_set(n))( bool2int(n[i]) ) + length(n) >= 1; % predicate array_bool_xor(array[int] of var bool: a) = .. sum(a) is odd .. %-----------------------------------------------------------------------------% % % Linear equations and inequations % %-----------------------------------------------------------------------------% predicate int_le_reif(var int: x, var int: y, var bool: b) = let { var 0..1: p = bool2int(b) } in aux_int_le_if_1(x, y, p) /\ aux_int_gt_if_0(x, y, p); predicate int_lt_reif(var int: x, var int: y, var bool: b) = int_le_reif(x, y - 1, b); predicate int_ne(var int: x, var int: y) = let { var 0..1: p } in aux_int_lt_if_1(x, y, p) /\ aux_int_gt_if_0(x, y, p); predicate int_lin_ne(array[int] of int: c, array[int] of var int: x, int: d) = int_ne(sum(i in index_set(x))( c[i]*x[i] ),d); predicate int_eq_reif(var int: x, var int: y, var bool: b) = aux_int_eq_iff_1(x, y, bool2int(b)); predicate int_ne_reif(var int: x, var int: y, var bool: b) = aux_int_eq_iff_1(x, y, 1 - bool2int(b)); %-----------------------------------------------------------------------------% predicate int_lin_eq_reif(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = aux_int_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, bool2int(b)); predicate int_lin_ne_reif(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = aux_int_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, 1 - bool2int(b)); predicate int_lin_le_reif(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = let { var 0..1: p = bool2int(b) } in aux_int_le_if_1(sum(i in index_set(x))( c[i] * x[i] ), d, p) /\ aux_int_gt_if_0(sum(i in index_set(x))( c[i] * x[i] ), d, p); predicate int_lin_lt_reif(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = int_lin_le_reif(c, x, d - 1, b); %-----------------------------------------------------------------------------% predicate float_le_reif(var float: x, var float: y, var bool: b) = let { var 0..1: p = bool2int(b) } in aux_float_le_if_1(x, y, int2float(p)) /\ aux_float_gt_if_0(x, y, int2float(p)); predicate float_lt_reif(var float: x, var float: y, var bool: b) = let { var 0..1: p = bool2int(b) } in aux_float_lt_if_1(x, y, int2float(p)) /\ aux_float_ge_if_0(x, y, int2float(p)); predicate float_ne(var float: x, var float: y) = let { var 0..1: p } in aux_float_lt_if_1(x, y, int2float(p)) /\ aux_float_gt_if_0(x, y, int2float(p)); predicate float_eq_reif(var float: x, var float: y, var bool: b) = aux_float_eq_iff_1(x, y, int2float(bool2int(b))); predicate float_ne_reif(var float: x, var float: y, var bool: b) = aux_float_eq_iff_1(x, y, 1.0 - int2float(bool2int(b))); %-----------------------------------------------------------------------------% predicate float_lin_eq_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = aux_float_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, int2float(bool2int(b))); predicate float_lin_ne_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = aux_float_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, 1.0 - int2float(bool2int(b))); predicate float_lin_le_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = let { var 0.0..1.0: p = int2float(bool2int(b)) } in aux_float_le_if_1(sum(i in index_set(x))( c[i] * x[i] ), d, p) /\ aux_float_gt_if_0(sum(i in index_set(x))( c[i] * x[i] ), d, p); predicate float_lin_lt_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = let { var 0.0..1.0: p = int2float(bool2int(b)) } in aux_float_lt_if_1(sum(i in index_set(x))( c[i] * x[i] ), d, p) /\ aux_float_ge_if_0(sum(i in index_set(x))( c[i] * x[i] ), d, p); %-----------------------------------------------------------------------------% % Minimum, maximum, absolute value predicate int_abs(var int: x, var int: z) = let { var 0..1: p } in % z <= x \/ z <= -x aux_int_le_if_1(z, x, p) /\ aux_int_le_if_0(z, -x, p) /\ z >= x /\ z >= -x /\ z >= 0; predicate int_min(var int: x, var int: y, var int: z) = let { var 0..1: p } in % z >= x \/ z >= y aux_int_ge_if_1(z, x, p) /\ aux_int_ge_if_0(z, y, p) /\ z <= x /\ z <= y; predicate int_max(var int: x, var int: y, var int: z) = let { var 0..1: p } in % z <= x \/ z <= y aux_int_le_if_1(z, x, p) /\ aux_int_le_if_0(z, y, p) /\ z >= x /\ z >= y; predicate float_abs(var float: x, var float: z) = let { var 0..1: p } in % z <= x \/ z <= -x aux_float_le_if_1(z, x, int2float(p)) /\ aux_float_le_if_0(z, -x, int2float(p)) /\ z >= x /\ z >= -x /\ z >= 0.0; predicate float_min(var float: x, var float: y, var float: z) = let { var 0..1: p } in % z >= x \/ z >= y aux_float_ge_if_1(z, x, int2float(p)) /\ aux_float_ge_if_0(z, y, int2float(p)) /\ z <= x /\ z <= y; predicate float_max(var float: x, var float: y, var float: z) = let { var 0..1: p } in % z <= x \/ z <= y aux_float_le_if_1(z, x, int2float(p)) /\ aux_float_le_if_0(z, y, int2float(p)) /\ z >= x /\ z >= y; %-----------------------------------------------------------------------------% % Multiplication and division predicate int_div(var int: x, var int: y, var int: q) = let { var 0..max(abs(lb(y)), abs(ub(y))) - 1: r } in aux_int_division_modulo(x,y,q,r); predicate int_mod(var int: x, var int: y, var int: r) = let { int: bx = max(abs(lb(x)), abs(ub(x))); var -bx..bx: q; int: by = max(abs(lb(y)), abs(ub(y))); constraint r in -by..by; } in aux_int_division_modulo(x,y,q,r); predicate aux_int_division_modulo(var int: x, var int: y, var int: q, var int: r) = x = y * q + r /\ let { array[1..2] of var 0..1: p } in % 0 < x -> 0 <= r which is 0 >= x \/ 0 <= r aux_int_le_if_1(x, 0, p[1]) /\ aux_int_ge_if_0(r, 0, p[1]) /\ % x < 0 -> r <= 0 which is x >= 0 \/ r <= 0 aux_int_ge_if_1(x, 0, p[2]) /\ aux_int_le_if_0(r, 0, p[2]) /\ % abs(r) < abs(y) let { var 1.. max(abs(lb(y)), abs(ub(y))): w = abs(y) } in w > r /\ w > -r; predicate int_times(var int: x, var int: y, var int: z) = if card(dom(x)) > card(dom(y)) then int_times(y,x,z) else let { set of int: s = lb(x)..ub(x), set of int: r = {lb(x)*lb(y), lb(x)*ub(y), ub(x)*lb(y), ub(x)*ub(y)}, array[s] of var min(r)..max(r): ady = array1d(s, [ d*y | d in s ]) } in ady[x] = z endif; %-----------------------------------------------------------------------------% % Array 'element' constraints predicate array_bool_element(var int: x, array[int] of bool: a, var bool: z) = x in index_set(a) /\ forall(d in index_set(a))( x = d -> a[d] = z ); predicate array_var_bool_element(var int: x, array[int] of var bool: a, var bool: z) = x in index_set(a) /\ forall(d in index_set(a))( x = d -> a[d] = z ); predicate array_int_element(var int: x, array[int] of int: a, var int: z) = x in index_set(a) /\ forall(d in index_set(a))( x = d -> a[d] = z ); predicate array_var_int_element(var int: x, array[int] of var int: a, var int: z) = x in index_set(a) /\ forall(d in index_set(a))( x = d -> a[d] = z ); predicate array_float_element(var int: x, array[int] of float: a, var float: z) = let { set of int: ix = index_set(a), array[ix] of var 0..1: x_eq_d } in sum(i in ix)( x_eq_d[i] ) = 1 /\ sum(i in ix)( i * x_eq_d[i] ) = x /\ sum(i in ix)( a[i] * int2float(x_eq_d[i]) ) = z; predicate array_var_float_element(var int: x, array[int] of var float: a, var float: z) = let { set of int: ix = index_set(a), array[ix] of var 0..1: x_eq_d } in sum(i in ix)( x_eq_d[i] ) = 1 /\ sum(i in ix)( i * x_eq_d[i] ) = x /\ forall(i in ix)( % x_eq_d[i] -> a[i] = a2[i] a[i] - z >= (lb(a[i])-ub(z))*int2float(1-x_eq_d[i]) /\ z - a[i] >= (lb(z)-ub(a[i]))*int2float(1-x_eq_d[i]) ); %-----------------------------------------------------------------------------% % Domain constraints % XXX only for a fixed set predicate set_in(var int: x, set of int: s) = if s = min(s)..max(s) then min(s) <= x /\ x <= max(s) else exists(e in s)( x = e ) endif; % XXX only for a fixed set predicate set_in_reif(var int: x, set of int: s, var bool: b) = b <-> exists(i in 1..length([ 0 | e in s where not (e - 1 in s) ]))( let { int: l = [ e | e in s where not (e - 1 in s) ][i], int: r = [ e | e in s where not (e + 1 in s) ][i] } in l <= x /\ x <= r ); % Alternative predicate alt_set_in_reif(var int: x, set of int: s, var bool: b) = b <-> if s = min(s)..max(s) then min(s) <= x /\ x <= max(s) else exists(e in s)( x = e ) endif; %-----------------------------------------------------------------------------% % Auxiliary: equality reified onto a 0/1 variable predicate aux_int_eq_iff_1(var int: x, var int: y, var int: p) = let { array[1..2] of var 0..1: q_458 } in aux_int_lt_if_0(x - p, y, q_458[1]) /\ aux_int_gt_if_0(x + p, y, q_458[2]) /\ sum(q_458) <= 2 - 2*p /\ sum(q_458) <= 1 + p; % Alternative 1 predicate alt_1_aux_int_eq_iff_1(var int: x, var int: y, var int: p) = let { array[1..2] of var 0..1: q } in aux_int_lt_if_0(x - p, y, q[1]) /\ aux_int_gt_if_0(x + p, y, q[2]) /\ q[1] <= 1 - p /\ q[2] <= 1 - p /\ sum(q) <= 1 + p; % Alternative 2 predicate alt_2_aux_int_eq_iff_1(var int: x, var int: y, var int: p) = let { array[1..2] of var 0..1: q } in aux_int_le_if_1(x, y, p) /\ aux_int_ge_if_1(x, y, p) /\ aux_int_lt_if_0(x, y, q[1]) /\ aux_int_gt_if_0(x, y, q[2]) /\ sum(q) <= p + 1; predicate aux_float_eq_iff_1(var float: x, var float: y, var float: p) = let { array[1..2] of var 0..1: q } in aux_float_le_if_1(x, y, p) /\ aux_float_ge_if_1(x, y, p) /\ aux_float_lt_if_0(x, y, int2float(q[1])) /\ aux_float_gt_if_0(x, y, int2float(q[2])) /\ int2float(sum(q)) <= 1.0 + p; %-----------------------------------------------------------------------------% % Auxiliary: indicator constraints % p -> x # 0 where p is a 0/1 variable and # is a comparison % Base cases predicate aux_int_le_zero_if_0(var int: x, var int: p) = x <= ub(x) * p; predicate aux_float_le_zero_if_0(var float: x, var float: p) = x <= ub(x) * p; predicate aux_float_lt_zero_if_0(var float: x, var float: p) = let { float: rho = 1e-02 * abs(ub(x)) } % same order of magnitude as ub(x) in x < (ub(x) + rho) * p; % Derived cases predicate aux_int_le_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y, p); predicate aux_int_ge_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x, p); predicate aux_int_le_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y, 1 - p); predicate aux_int_ge_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x, 1 - p); predicate aux_int_lt_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y + 1, p); predicate aux_int_gt_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x + 1, p); predicate aux_int_lt_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y + 1, 1 - p); predicate aux_float_le_if_0(var float: x, var float: y, var float: p) = aux_float_le_zero_if_0(x - y, p); predicate aux_float_ge_if_0(var float: x, var float: y, var float: p) = aux_float_le_zero_if_0(y - x, p); predicate aux_float_le_if_1(var float: x, var float: y, var float: p) = aux_float_le_zero_if_0(x - y, 1.0 - p); predicate aux_float_ge_if_1(var float: x, var float: y, var float: p) = aux_float_le_zero_if_0(y - x, 1.0 - p); predicate aux_float_lt_if_0(var float: x, var float: y, var float: p) = aux_float_lt_zero_if_0(x - y, p); predicate aux_float_gt_if_0(var float: x, var float: y, var float: p) = aux_float_lt_zero_if_0(y - x, p); predicate aux_float_lt_if_1(var float: x, var float: y, var float: p) = aux_float_lt_zero_if_0(x - y, 1.0 - p); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% annotation bool_search(array[int] of var bool: x, ann:a1, ann:a2, ann:a3) = int_search([bool2int(x[i]) | i in index_set(x)],a1,a2,a3); predicate array_int_maximum(var int: m, array[int] of var int: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), int: ly = lb_array(x), int: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == max(x[i],y[i-1]) ); predicate array_float_maximum(var float: m, array[int] of var float: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), float: ly = lb_array(x), float: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == max(x[i],y[i-1]) ); predicate array_int_minimum(var int: m, array[int] of var int: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), int: ly = lb_array(x), int: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == min(x[i],y[i-1]) ); predicate array_float_minimum(var float: m, array[int] of var float: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), float: ly = lb_array(x), float: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == min(x[i],y[i-1]) ); mzn_opt_only_range_domains = true; libminizinc-2.4.2/share/minizinc/linear_old/linear/table_int.mzn000066400000000000000000000016061360574160400250320ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % A 'table' constraint table(x, T) represents the constraint x in T where we % consider each row in T to be a tuple and T as a set of tuples. % % Linear version. % % See also the equality encoding of the 'element' constraint. %-----------------------------------------------------------------------------% predicate table_int(array[int] of var int: x, array[int, int] of int: t) = assert(index_set_2of2(t) = index_set(x), "The second dimension of the table must equal the number of " ++ "variables in the first argument", let { set of int: it = index_set_1of2(t), array[it] of var 0..1: lambda } in sum(lambda) = 1 /\ forall(j in index_set(x))( sum(i in it)( t[i,j]*lambda[i] ) = x[j] ) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/linear_old/redefinitions-2.0.2.mzn000066400000000000000000000014711360574160400251160ustar00rootroot00000000000000% This file contains redefinitions of standard builtins for version 2.0.2 % that can be overridden by solvers. predicate symmetry_breaking_constraint(var bool: b) = b; predicate redundant_constraint(var bool: b) = b; %% Linearized element: just call without shifting predicate array_var_bool_element_nonshifted(var int: idx, array[int] of var bool: x, var bool: c) = array_var_bool_element(idx,x,c); predicate array_var_int_element_nonshifted(var int: idx, array[int] of var int: x, var int: c) = array_var_int_element(idx,x,c); predicate array_var_float_element_nonshifted(var int: idx, array[int] of var float: x, var float: c) = array_var_float_element(idx,x,c); predicate array_var_set_element_nonshifted(var int: idx, array[int] of var set of int: x, var set of int: c) = array_var_set_element(idx,x,c); libminizinc-2.4.2/share/minizinc/linear_old/redefinitions-2.0.mzn000066400000000000000000000003561360574160400247570ustar00rootroot00000000000000predicate bool_clause_reif(array[int] of var bool: p, array[int] of var bool: n, var bool: c) = c = ( sum(i in index_set(p))( bool2int(p[i]) ) - sum(i in index_set(n))( bool2int(n[i]) ) + length(n) >= 1 ); libminizinc-2.4.2/share/minizinc/linear_old/redefinitions.mzn000066400000000000000000000451121360574160400244610ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % FlatZinc built-in redefinitions for linear solvers. % % Sebastian Brand % Gleb Belov Corrected array_var_float_element and float_lin_lt_reif %-----------------------------------------------------------------------------% function var bool: reverse_map(var int: x) = (x==1); function bool: reverse_map(int: x) = (x==1); function var int: bool2int(var bool: x) :: promise_total = let { var 0..1: b2i; constraint (x = reverse_map(b2i)) ::is_reverse_map ; } in b2i; predicate bool_eq(var bool: x, var bool: y) = bool2int(x)==bool2int(y); %-----------------------------------------------------------------------------% % Strict inequality % % Uncomment the following redefinition for FlatZinc MIP solver interfaces that % do not support strict inequality. Note that it does not preserve equivalence % (some solutions of the original problem may become invalid). % predicate float_lt(var float: x, var float: y) = x + 1e-06 <= y; %-----------------------------------------------------------------------------% % % Logic operations % %-----------------------------------------------------------------------------% predicate bool_not(var bool: p, var bool: q) = let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q) } in x + y = 1; predicate bool_and(var bool: p, var bool: q, var bool: r) = let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q), var 0..1: z = bool2int(r) } in x + y <= z + 1 /\ x + y >= z * 2; % x >= z /\ y >= z; % alternative predicate bool_or(var bool: p, var bool: q, var bool: r) = let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q), var 0..1: z = bool2int(r) } in x + y >= z /\ x + y <= z * 2; % x <= z /\ y <= z; % alternative predicate bool_xor(var bool: p, var bool: q, var bool: r) = let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q), var 0..1: z = bool2int(r) } in x <= y + z /\ y <= x + z /\ z <= x + y /\ x + y + z <= 2; predicate bool_eq_reif(var bool: p, var bool: q, var bool: r) = if is_fixed(q) then % frequent case if fix(q) = true then p = r else bool_not(p,r) endif else let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q), var 0..1: z = bool2int(r) } in x + y <= z + 1 /\ x + z <= y + 1 /\ y + z <= x + 1 /\ x + y + z >= 1 endif; predicate bool_ne_reif(var bool: p, var bool: q, var bool: r) = bool_xor(p, q, r); predicate bool_le(var bool: p, var bool: q) = let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q) } in x <= y; predicate bool_le_reif(var bool: p, var bool: q, var bool: r) = let { var 0..1: x = bool2int(p), var 0..1: y = bool2int(q), var 0..1: z = bool2int(r) } in 1 - x + y >= z /\ 1 - x + y <= z * 2; % 1 - x <= z /\ y <= z; % alternative predicate bool_lt(var bool: p, var bool: q) = not p /\ q; predicate bool_lt_reif(var bool: p, var bool: q, var bool: r) = (not p /\ q) <-> r; %-----------------------------------------------------------------------------% predicate array_bool_or(array[int] of var bool: a, var bool: b) = if is_fixed(b) then % frequent case if fix(b) = true then sum(i in index_set(a))( bool2int(a[i]) ) >= 1 else forall(i in index_set(a))( not a[i] ) endif else let { var 0..1: x = bool2int(b), array[1..length(a)] of var 0..1: c = [ bool2int(a[i]) | i in index_set(a) ] } in sum(c) >= x /\ sum(c) <= x * length(a) endif; predicate array_bool_and(array[int] of var bool: a, var bool: b) = let { var 0..1: x = bool2int(b), array[1..length(a)] of var 0..1: c = [ bool2int(a[i]) | i in index_set(a) ] } in length(a) - sum(c) >= 1 - x /\ length(a) - sum(c) <= (1 - x) * length(a); predicate array_bool_xor(array[int] of var bool: a) = let { var 0..length(a): m } in sum(i in 1..length(a))( bool2int(a[i]) ) = 1 + 2 * m; predicate bool_clause(array[int] of var bool: p, array[int] of var bool: n) = sum(i in index_set(p))( bool2int(p[i]) ) - sum(i in index_set(n))( bool2int(n[i]) ) + length(n) >= 1; % predicate array_bool_xor(array[int] of var bool: a) = .. sum(a) is odd .. %-----------------------------------------------------------------------------% % % Linear equations and inequations % %-----------------------------------------------------------------------------% predicate int_le_reif(var int: x, var int: y, var bool: b) = let { var 0..1: p = bool2int(b) } in aux_int_le_if_1(x, y, p) /\ aux_int_gt_if_0(x, y, p); predicate int_lt_reif(var int: x, var int: y, var bool: b) = int_le_reif(x, y - 1, b); predicate int_ne(var int: x, var int: y) = let { var 0..1: p } in aux_int_lt_if_1(x, y, p) /\ aux_int_gt_if_0(x, y, p); predicate int_lin_ne(array[int] of int: c, array[int] of var int: x, int: d) = int_ne(sum(i in index_set(x))( c[i]*x[i] ),d); predicate int_eq_reif(var int: x, var int: y, var bool: b) = aux_int_eq_iff_1(x, y, bool2int(b)); predicate int_ne_reif(var int: x, var int: y, var bool: b) = aux_int_eq_iff_1(x, y, 1 - bool2int(b)); %-----------------------------------------------------------------------------% predicate int_lin_eq_reif(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = aux_int_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, bool2int(b)); predicate int_lin_ne_reif(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = aux_int_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, 1 - bool2int(b)); predicate int_lin_le_reif(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = let { var 0..1: p = bool2int(b) } in aux_int_le_if_1(sum(i in index_set(x))( c[i] * x[i] ), d, p) /\ aux_int_gt_if_0(sum(i in index_set(x))( c[i] * x[i] ), d, p); predicate int_lin_lt_reif(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = int_lin_le_reif(c, x, d - 1, b); %-----------------------------------------------------------------------------% predicate float_le_reif(var float: x, var float: y, var bool: b) = let { var 0..1: p = bool2int(b) } in aux_float_le_if_1(x, y, int2float(p)) /\ aux_float_gt_if_0(x, y, int2float(p)); predicate float_lt_reif(var float: x, var float: y, var bool: b) = let { var 0..1: p = bool2int(b) } in aux_float_lt_if_1(x, y, int2float(p)) /\ aux_float_ge_if_0(x, y, int2float(p)); predicate float_ne(var float: x, var float: y) = let { var 0..1: p } in aux_float_lt_if_1(x, y, int2float(p)) /\ aux_float_gt_if_0(x, y, int2float(p)); predicate float_eq_reif(var float: x, var float: y, var bool: b) = aux_float_eq_iff_1(x, y, int2float(bool2int(b))); predicate float_ne_reif(var float: x, var float: y, var bool: b) = aux_float_eq_iff_1(x, y, 1.0 - int2float(bool2int(b))); %-----------------------------------------------------------------------------% predicate float_lin_eq_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = aux_float_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, int2float(bool2int(b))); predicate float_lin_ne_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = aux_float_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, 1.0 - int2float(bool2int(b))); predicate float_lin_le_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = let { var 0.0..1.0: p = int2float(bool2int(b)) } in aux_float_le_if_1(sum(i in index_set(x))( c[i] * x[i] ), d, p) /\ aux_float_gt_if_0(sum(i in index_set(x))( c[i] * x[i] ), d, p); predicate float_lin_lt_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = let { var 0.0..1.0: p = int2float(bool2int(b)) } in aux_float_lt_if_1(sum(i in index_set(x))( c[i] * x[i] ), d, p) /\ aux_float_ge_if_0(sum(i in index_set(x))( c[i] * x[i] ), d, p); %-----------------------------------------------------------------------------% % Minimum, maximum, absolute value predicate int_abs(var int: x, var int: z) = let { var 0..1: p } in % z <= x \/ z <= -x aux_int_le_if_1(z, x, p) /\ aux_int_le_if_0(z, -x, p) /\ z >= x /\ z >= -x /\ z >= 0; predicate int_min(var int: x, var int: y, var int: z) = let { var 0..1: p } in % z >= x \/ z >= y aux_int_ge_if_1(z, x, p) /\ aux_int_ge_if_0(z, y, p) /\ z <= x /\ z <= y; predicate int_max(var int: x, var int: y, var int: z) = let { var 0..1: p } in % z <= x \/ z <= y aux_int_le_if_1(z, x, p) /\ aux_int_le_if_0(z, y, p) /\ z >= x /\ z >= y; predicate float_abs(var float: x, var float: z) = let { var 0..1: p } in % z <= x \/ z <= -x aux_float_le_if_1(z, x, int2float(p)) /\ aux_float_le_if_0(z, -x, int2float(p)) /\ z >= x /\ z >= -x /\ z >= 0.0; predicate float_min(var float: x, var float: y, var float: z) = let { var 0..1: p } in % z >= x \/ z >= y aux_float_ge_if_1(z, x, int2float(p)) /\ aux_float_ge_if_0(z, y, int2float(p)) /\ z <= x /\ z <= y; predicate float_max(var float: x, var float: y, var float: z) = let { var 0..1: p } in % z <= x \/ z <= y aux_float_le_if_1(z, x, int2float(p)) /\ aux_float_le_if_0(z, y, int2float(p)) /\ z >= x /\ z >= y; %-----------------------------------------------------------------------------% % Multiplication and division predicate int_div(var int: x, var int: y, var int: q) = let { var 0..max(abs(lb(y)), abs(ub(y))) - 1: r } in aux_int_division_modulo(x,y,q,r); predicate int_mod(var int: x, var int: y, var int: r) = let { int: bx = max(abs(lb(x)), abs(ub(x))); var -bx..bx: q; int: by = max(abs(lb(y)), abs(ub(y))); constraint r in -by..by; } in aux_int_division_modulo(x,y,q,r); predicate aux_int_division_modulo(var int: x, var int: y, var int: q, var int: r) = x = y * q + r /\ let { array[1..2] of var 0..1: p } in % 0 < x -> 0 <= r which is 0 >= x \/ 0 <= r aux_int_le_if_1(x, 0, p[1]) /\ aux_int_ge_if_0(r, 0, p[1]) /\ % x < 0 -> r <= 0 which is x >= 0 \/ r <= 0 aux_int_ge_if_1(x, 0, p[2]) /\ aux_int_le_if_0(r, 0, p[2]) /\ % abs(r) < abs(y) let { var 1.. max(abs(lb(y)), abs(ub(y))): w = abs(y) } in w > r /\ w > -r; predicate int_times(var int: x, var int: y, var int: z) = if card(dom(x)) > card(dom(y)) then int_times(y,x,z) else let { set of int: s = lb(x)..ub(x), set of int: r = {lb(x)*lb(y), lb(x)*ub(y), ub(x)*lb(y), ub(x)*ub(y)}, array[s] of var min(r)..max(r): ady = array1d(s, [ d*y | d in s ]) } in ady[x] = z endif; %-----------------------------------------------------------------------------% % Array 'element' constraints predicate array_bool_element(var int: x, array[int] of bool: a, var bool: z) = x in index_set(a) /\ forall(d in index_set(a))( x = d -> a[d] = z ); predicate array_var_bool_element(var int: x, array[int] of var bool: a, var bool: z) = x in index_set(a) /\ forall(d in index_set(a))( x = d -> a[d] = z ); predicate array_int_element(var int: x, array[int] of int: a, var int: z) = x in index_set(a) /\ forall(d in index_set(a))( x = d -> a[d] = z ); predicate array_var_int_element(var int: x, array[int] of var int: a, var int: z) = x in index_set(a) /\ forall(d in index_set(a))( x = d -> a[d] = z ); predicate array_float_element(var int: x, array[int] of float: a, var float: z) = let { set of int: ix = index_set(a), array[ix] of var 0..1: x_eq_d } in sum(i in ix)( x_eq_d[i] ) = 1 /\ sum(i in ix)( i * x_eq_d[i] ) = x /\ sum(i in ix)( a[i] * int2float(x_eq_d[i]) ) = z; predicate array_var_float_element(var int: x, array[int] of var float: a, var float: z) = let { set of int: ix = index_set(a), array[ix] of var 0..1: x_eq_d } in sum(i in ix)( x_eq_d[i] ) = 1 /\ sum(i in ix)( i * x_eq_d[i] ) = x /\ forall(i in ix)( % x_eq_d[i] -> a[i] = a2[i] a[i] - z >= (lb(a[i])-ub(z))*int2float(1-x_eq_d[i]) /\ z - a[i] >= (lb(z)-ub(a[i]))*int2float(1-x_eq_d[i]) ); %-----------------------------------------------------------------------------% % Domain constraints % XXX only for a fixed set predicate set_in(var int: x, set of int: s) = if s = min(s)..max(s) then min(s) <= x /\ x <= max(s) else exists(e in s)( x = e ) endif; % XXX only for a fixed set predicate set_in_reif(var int: x, set of int: s, var bool: b) = b <-> exists(i in 1..length([ 0 | e in s where not (e - 1 in s) ]))( let { int: l = [ e | e in s where not (e - 1 in s) ][i], int: r = [ e | e in s where not (e + 1 in s) ][i] } in l <= x /\ x <= r ); % Alternative predicate alt_set_in_reif(var int: x, set of int: s, var bool: b) = b <-> if s = min(s)..max(s) then min(s) <= x /\ x <= max(s) else exists(e in s)( x = e ) endif; %-----------------------------------------------------------------------------% % Auxiliary: equality reified onto a 0/1 variable predicate aux_int_eq_iff_1(var int: x, var int: y, var int: p) = let { array[1..2] of var 0..1: q_458 } in aux_int_lt_if_0(x - p, y, q_458[1]) /\ aux_int_gt_if_0(x + p, y, q_458[2]) /\ sum(q_458) <= 2 - 2*p /\ sum(q_458) <= 1 + p; % Alternative 1 predicate alt_1_aux_int_eq_iff_1(var int: x, var int: y, var int: p) = let { array[1..2] of var 0..1: q } in aux_int_lt_if_0(x - p, y, q[1]) /\ aux_int_gt_if_0(x + p, y, q[2]) /\ q[1] <= 1 - p /\ q[2] <= 1 - p /\ sum(q) <= 1 + p; % Alternative 2 predicate alt_2_aux_int_eq_iff_1(var int: x, var int: y, var int: p) = let { array[1..2] of var 0..1: q } in aux_int_le_if_1(x, y, p) /\ aux_int_ge_if_1(x, y, p) /\ aux_int_lt_if_0(x, y, q[1]) /\ aux_int_gt_if_0(x, y, q[2]) /\ sum(q) <= p + 1; predicate aux_float_eq_iff_1(var float: x, var float: y, var float: p) = let { array[1..2] of var 0..1: q } in aux_float_le_if_1(x, y, p) /\ aux_float_ge_if_1(x, y, p) /\ aux_float_lt_if_0(x, y, int2float(q[1])) /\ aux_float_gt_if_0(x, y, int2float(q[2])) /\ int2float(sum(q)) <= 1.0 + p; %-----------------------------------------------------------------------------% % Auxiliary: indicator constraints % p -> x # 0 where p is a 0/1 variable and # is a comparison % Base cases predicate aux_int_le_zero_if_0(var int: x, var int: p) = x <= ub(x) * p; predicate aux_float_le_zero_if_0(var float: x, var float: p) = x <= ub(x) * p; predicate aux_float_lt_zero_if_0(var float: x, var float: p) = let { float: rho = 1e-02 * abs(ub(x)) } % same order of magnitude as ub(x) in x < (ub(x) + rho) * p; % Derived cases predicate aux_int_le_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y, p); predicate aux_int_ge_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x, p); predicate aux_int_le_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y, 1 - p); predicate aux_int_ge_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x, 1 - p); predicate aux_int_lt_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y + 1, p); predicate aux_int_gt_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x + 1, p); predicate aux_int_lt_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y + 1, 1 - p); predicate aux_float_le_if_0(var float: x, var float: y, var float: p) = aux_float_le_zero_if_0(x - y, p); predicate aux_float_ge_if_0(var float: x, var float: y, var float: p) = aux_float_le_zero_if_0(y - x, p); predicate aux_float_le_if_1(var float: x, var float: y, var float: p) = aux_float_le_zero_if_0(x - y, 1.0 - p); predicate aux_float_ge_if_1(var float: x, var float: y, var float: p) = aux_float_le_zero_if_0(y - x, 1.0 - p); predicate aux_float_lt_if_0(var float: x, var float: y, var float: p) = aux_float_lt_zero_if_0(x - y, p); predicate aux_float_gt_if_0(var float: x, var float: y, var float: p) = aux_float_lt_zero_if_0(y - x, p); predicate aux_float_lt_if_1(var float: x, var float: y, var float: p) = aux_float_lt_zero_if_0(x - y, 1.0 - p); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% annotation bool_search(array[int] of var bool: x, ann:a1, ann:a2, ann:a3) = int_search([bool2int(x[i]) | i in index_set(x)],a1,a2,a3); predicate array_int_maximum(var int: m, array[int] of var int: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), int: ly = lb_array(x), int: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == max(x[i],y[i-1]) ); predicate array_float_maximum(var float: m, array[int] of var float: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), float: ly = lb_array(x), float: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == max(x[i],y[i-1]) ); predicate array_int_minimum(var int: m, array[int] of var int: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), int: ly = lb_array(x), int: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == min(x[i],y[i-1]) ); predicate array_float_minimum(var float: m, array[int] of var float: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), float: ly = lb_array(x), float: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == min(x[i],y[i-1]) ); mzn_opt_only_range_domains = true; libminizinc-2.4.2/share/minizinc/linear_old/table_int.mzn000066400000000000000000000016061360574160400235600ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % A 'table' constraint table(x, T) represents the constraint x in T where we % consider each row in T to be a tuple and T as a set of tuples. % % Linear version. % % See also the equality encoding of the 'element' constraint. %-----------------------------------------------------------------------------% predicate table_int(array[int] of var int: x, array[int, int] of int: t) = assert(index_set_2of2(t) = index_set(x), "The second dimension of the table must equal the number of " ++ "variables in the first argument", let { set of int: it = index_set_1of2(t), array[it] of var 0..1: lambda } in sum(lambda) = 1 /\ forall(j in index_set(x))( sum(i in it)( t[i,j]*lambda[i] ) = x[j] ) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/linear_scip/000077500000000000000000000000001360574160400212465ustar00rootroot00000000000000libminizinc-2.4.2/share/minizinc/linear_scip/README__SCIP.txt000066400000000000000000000001331360574160400237160ustar00rootroot000000000000002019-05-06 Currently need to copy the whole linear directory to specialize it for SCIP. libminizinc-2.4.2/share/minizinc/linear_scip/domain_encodings.mzn000066400000000000000000000103361360574160400252770ustar00rootroot00000000000000/*%-----------------------------------------------------------------------------% % Domain encodings %-----------------------------------------------------------------------------% */ % Linear equality encoding % Single variable: x = d <-> x_eq_d[d] predicate equality_encoding(var int: x, array[int] of var int: x_eq_d) = x in index_set(x_eq_d) /\ sum(d in dom(x))( x_eq_d[d] ) = 1 /\ sum(d in dom(x))( d * x_eq_d[d] ) = x /\ % my_trace( "eq_enc: \(x), index_set(pp)=" ++ show(index_set( x_eq_d )) ++ "\n" ) /\ if fPostprocessDomains then equality_encoding__POST(x, x_eq_d) else true endif ; % Two variables: x = d /\ y = e <-> x_eq_d[d] /\ y_eq_e[e] /\ xy_eq_de[d, e] predicate equality_encoding(var int: x, var int: y, array[int] of var int: x_eq_d, array[int] of var int: y_eq_e, array[int, int] of var int: xy_eq_de ) = x in index_set(x_eq_d) /\ y in index_set(y_eq_e) /\ index_set(x_eq_d) == index_set_1of2(xy_eq_de) /\ index_set(y_eq_e) == index_set_2of2(xy_eq_de) /\ sum(d in dom(x), e in dom(y))( xy_eq_de[d, e] ) = 1 /\ forall(d in dom(x)) (sum(e in dom(y))( xy_eq_de[d, e] ) = x_eq_d[d]) /\ forall(e in dom(y)) (sum(d in dom(x))( xy_eq_de[d, e] ) = y_eq_e[e]) ; % Array of variables: x[i] = d <-> x_eq_d[i,d] predicate equality_encoding(array[int] of var int: x, array[int, int] of var int: x_eq_d) = forall(i in index_set(x))( x[i] in index_set_2of2(x_eq_d) /\ sum(d in index_set_2of2(x_eq_d))( x_eq_d[i,d] ) = 1 /\ sum(d in index_set_2of2(x_eq_d))( d * x_eq_d[i,d] ) = x[i] ); function var int: eq_new_var(var int: x, int: i) ::promise_total = if i in dom(x) then let { var 0..1: xi; } in xi else 0 endif; function array[int] of var int: eq_encode(var int: x) ::promise_total = let { array[int] of var int: y = array1d(lb(x)..ub(x),[eq_new_var(x,i) | i in lb(x)..ub(x)]); constraint equality_encoding(x,y); % constraint % if card(dom(x))>0 then % my_trace(" eq_encode: dom(\(x)) = " ++ show(dom(x)) ++ ", card( dom(\(x)) ) = " ++ show(card(dom(x))) ++ "\n") % else true endif; %% constraint assert(card(dom(x))>1, " eq_encode: card(dom(\(x))) == " ++ show(card(dom(x)))); } in y; function array[int] of int: eq_encode(int: x) ::promise_total = array1d(lb(x)..ub(x),[ if i=x then 1 else 0 endif | i in lb(x)..ub(x)]); %%% The same for 2 variables: function var int: eq_new_var(var int: x, int: i, var int: y, int: j) ::promise_total = if i in dom(x) /\ j in dom(y) then let { var 0..1: xi; } in xi else 0 endif; function array[int, int] of var int: eq_encode(var int: x, var int: y) ::promise_total = let { array[int] of var int: pX = eq_encode(x), array[int] of var int: pY = eq_encode(y), array[int, int] of var int: pp = array2d(index_set(pX), index_set(pY), [eq_new_var(x,i,y,j) | i in index_set(pX), j in index_set(pY)]); constraint equality_encoding(x, y, pX, pY, pp); } in pp; function array[int, int] of int: eq_encode(int: x, int: y) ::promise_total = % let { % constraint if card(dom(x))*card(dom(y))>200 then % my_trace(" eq_encode: dom(\(x)) = " ++ show(dom(x)) ++ ", dom(\(y)) = " ++ show(dom(y)) ++ "\n") % else true endif; % } in array2d(lb(x)..ub(x), lb(y)..ub(y), [if i==x /\ j==y then 1 else 0 endif | i in lb(x)..ub(x), j in lb(y)..ub(y)]); function array[int,int] of var int: eq_encode(array[int] of var int: x) ::promise_total = let { array[index_set(x),lb_array(x)..ub_array(x)] of var int: y = array2d(index_set(x),lb_array(x)..ub_array(x), [ let { array[int] of var int: xi = eq_encode(x[i]) } in if j in index_set(xi) then xi[j] else 0 endif | i in index_set(x), j in lb_array(x)..ub_array(x)] ) } in y; function array[int,int] of int: eq_encode(array[int] of int: x) ::promise_total = array2d(index_set(x),lb_array(x)..ub_array(x),[ if j=x[i] then 1 else 0 endif | i in index_set(x), j in lb_array(x)..ub_array(x)]); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/linear_scip/fzn_all_different_int.mzn000066400000000000000000000015251360574160400263240ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % 'all_different' constrains an array of objects to be all different. % % Linear version: equality encoding; see e.g. [Refalo, CP 2000] % % For a given d in dom(x), at most one i with x_i = d can exist. %-----------------------------------------------------------------------------% include "domain_encodings.mzn"; predicate fzn_all_different_int(array[int] of var int: x) = if length(x)<=1 then true else let { array[int,int] of var 0..1: x_eq_d = eq_encode(x) } in ( % my_trace(" all_different_int: x[" ++ show(index_set(x)) ++ "]\n") /\ forall(d in index_set_2of2(x_eq_d))( sum(i in index_set_1of2(x_eq_d))( x_eq_d[i,d] ) <= 1 ) ) endif; %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/linear_scip/fzn_alldifferent_except_0.mzn000066400000000000000000000012211360574160400270730ustar00rootroot00000000000000/** @group globals.alldifferent Constrain the array of integers \a vs to be all different except those elements that are assigned the value 0. */ predicate fzn_alldifferent_except_0(array[int] of var int: vs) = % forall(i, j in index_set(vs) where i < j) ( % (vs[i] != 0 /\ vs[j] != 0) -> vs[i] != vs[j] % ); if length(vs)<=1 then true else let { array[int,int] of var 0..1: x_eq_d = eq_encode(vs) } in ( % my_trace(" alldifferent_except_0: x[" ++ show(index_set(vs)) ++ "]\n") /\ forall(d in index_set_2of2(x_eq_d) diff {0})( sum(i in index_set_1of2(x_eq_d))( x_eq_d[i,d] ) <= 1 ) ) endif; libminizinc-2.4.2/share/minizinc/linear_scip/fzn_circuit.mzn000066400000000000000000000035031360574160400243140ustar00rootroot00000000000000include "alldifferent.mzn"; /** @group globals Constrains the elements of \a x to define a circuit where \a x[\p i] = \p j means that \p j is the successor of \p i. */ % Linear version. predicate fzn_circuit(array[int] of var int: x) = let { set of int: S = index_set(x), int: l = min(S), int: u = max(S), int: n = card(S), constraint forall( i in S )( x[i] in S diff {i} ), %% Self-mapping and exclude i->i before alldifferent } in alldifferent(x) /\ % alldifferent(order) /\ if nMZN__fSECcuts>0 then let { array [int, int] of var int: eq_x = eq_encode( x ), constraint assert( l==min( index_set_2of2( eq_x ) ), "circuit: index set mismatch" ), %% self-mapping constraint assert( u==max( index_set_2of2( eq_x ) ), "circuit: index set mismatch" ), } in circuit__SECcuts( eq_x ) else true endif /\ if nMZN__fSECcuts<2 then %%% MTZ model. Note that INTEGER order vars seem better!: let { array[l+1..l+n-1] of var 2..n: order, } in forall (i,j in l+1..l+n-1 where i!=j /\ j in dom(x[i])) ( order[i] - order[j] + (n-1)* bool2int(x[i]==j) + (n-3)*bool2int(x[j]==i) %% the Desrochers & Laporte '91 term %%%% --- strangely enough it is much worse on vrp-s2-v2-c7_vrp-v2-c7_det_ADAPT_1_INVERSE.mzn! <= n-2 ) else true endif %% ... but seems improved with this (leaving also for SEC) /\ if n>2 then forall (i,j in S where i= 0 and \a r[\p i] >= 0 Linear version. */ %% A global cumulative with SCIP predicate fzn_cumulative(array[int] of var int: s, array[int] of int: d, array[int] of int: r, int: b); predicate fzn_cumulative(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = assert(index_set(s) == index_set(d) /\ index_set(s) == index_set(r), "cumulative: the 3 array arguments must have identical index sets", if 0==length(s) then true else assert(lb_array(d) >= 0 /\ lb_array(r) >= 0, "cumulative: durations and resource usages must be non-negative", if mzn_in_redundant_constraint() /\ fMZN__IgnoreRedundantCumulative then true else let { set of int: tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 }, set of int: times = dom_array( [ s[i] | i in tasks ] ) } in if 0==card(tasks) then /*true*/ 0==card(index_set(s)) \/ b>=0 else if nMZN__UnarySizeMax_cumul>=card(times)*card(tasks) then %%% -- Mem overflow on rcmsp. PARAMETER? TODO cumulative_time_decomp(s, d, r, b, times) else cumulative_task_decomp(s, d, r, b) endif endif endif ) endif ); %% Can be called with a given set of times: predicate cumulative_set_times(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b, set of int: TIMES01) = assert(index_set(s) == index_set(d) /\ index_set(s) == index_set(r), "cumulative: the 3 array arguments must have identical index sets", assert(lb_array(d) >= 0 /\ lb_array(r) >= 0, "cumulative: durations and resource usages must be non-negative", let { set of int: tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 }, set of int: times = dom_array( [ s[i] | i in tasks ] ) intersect TIMES01 } in if false then %%% 100>=card(times) then %% PARAMETER ? cumulative_time_decomp(s, d, r, b, times) else cumulative_task_decomp(s, d, r, b) endif )); predicate cumulative_time_decomp(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b, set of int: TIMES01) = let { set of int: tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 }, set of int: times = { i | i in min([ lb(s[i]) | i in tasks ]) .. max([ ub(s[i]) + ub(d[i]) | i in tasks ]) where i in TIMES01 } } in % my_trace(" cumul_time: " ++ show(card(tasks)) ++ " tasks, " ++ show(card(times)) ++ " times\n") /\ forall( t in times ) ( b >= sum( i in tasks ) ( if is_fixed(d[i]) then bool2int( s[i] in t-fix(d[i])+1..t ) else bool2int( s[i] <= t /\ t < s[i] + d[i] ) endif * r[i] ) ); predicate cumulative_task_decomp(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = let { set of int: tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 } } in % my_trace(" cumul_tasks: " ++ show(card(tasks)) ++ " tasks\n") /\ forall( j in tasks) ( b-r[j] >= sum( i in tasks where i != j /\ lb(s[i])<=ub(s[j]) /\ lb(s[j])= c[i]) /\ sum(d)=1 /\ y = sum (i in index_set(c)) ( d[i]*x[i] ); libminizinc-2.4.2/share/minizinc/linear_scip/fzn_if_then_else_int.mzn000066400000000000000000000004271360574160400261520ustar00rootroot00000000000000predicate fzn_if_then_else_int(array[int] of var bool: c, array[int] of int: x, var int: y) = let { array[index_set(c)] of var 0..1: d; } in forall (i in index_set(c)) (sum(j in 1..i-1)(c[j])+d[i] >= c[i]) /\ sum(d)=1 /\ y = sum (i in index_set(c)) ( d[i]*x[i] ); libminizinc-2.4.2/share/minizinc/linear_scip/fzn_inverse.mzn000066400000000000000000000022231360574160400243230ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Constrains two arrays of int variables to represent inverse functions. % All the values in each array must be within the index set of the other array. % % Linear version. %-----------------------------------------------------------------------------% % include "domain_encodings.mzn"; % predicate inverse(array[int] of var int: f, array[int] of var int: g) = % let { % array[int,int] of var 0..1: map_f = eq_encode(f); % array[int,int] of var 0..1: map_g = eq_encode(g); % } in forall (i in index_set(f), j in index_set(g)) (map_f[i,j] = map_g[j,i]); %-----------------------------------------------------------------------------% %% Now copying the std version, seems a little faster on vrp-s2-v2-c7_vrp-v2-c7_det_ADAPT_1_INVERSE.mzn predicate fzn_inverse(array[int] of var int: f, array[int] of var int: invf) = forall(i in index_set(f)) ( f[i] in index_set(invf) ) /\ forall(j in index_set(invf)) ( invf[j] in index_set(f) ) /\ forall(i in index_set(f), j in index_set(invf)) ( ((j == f[i]) <-> (i == invf[j])) ); libminizinc-2.4.2/share/minizinc/linear_scip/fzn_lex_less_bool_reif.mzn000066400000000000000000000012461360574160400265120ustar00rootroot00000000000000include "../std/fzn_lex_less_bool_reif.mzn"; predicate fzn_lex_less_bool_imp(array[int] of var bool: x, array[int] of var bool: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = max(ux - lx, uy - ly), array[0..size+1] of var bool: b } in (c -> b[0]) /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx < uy - ly); libminizinc-2.4.2/share/minizinc/linear_scip/fzn_lex_lesseq_bool.mzn000066400000000000000000000042401360574160400260300ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is lexicographically less than or equal to % array 'y'. Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate fzn_lex_lesseq_bool(array[int] of var bool: x, array[int] of var bool: y) = % if (min(card(index_set(x)), card(index_set(y))) <= 25) then % let { int: size = min(card(index_set(x)), card(index_set(y))); % } in % sum(i in 0..size-1)(pow(2, (size-1-i)) * bool2int(x[i+min(index_set(x))])) % <= sum(i in 0..size-1)(pow(2, (size-1-i)) * bool2int(y[i+min(index_set(y))])) % else % my_trace ("lex_lesseq_bool(\(x), \(y))") /\ let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = min(ux - lx, uy - ly), array[0..size+1] of var bool: b } % b[i] is true if the lexicographical order holds from position i on. in b[0] /\ forall(i in 0..size) ( b[i] -> ( ( ( x[lx + i] <= y[ly + i] ) ) /\ % bool2int(b[i]) + bool2int(x[lx + i]) + (1-bool2int(y[ly + i])) <= 2 /\ % ( b[i] -> ( x[lx + i] < y[ly + i] \/ b[i+1] ) ) % /\ ( bool2int(b[i]) <= bool2int(x[lx + i] < y[ly + i]) + bool2int(b[i+1]) ) /\ % bool2int(b[i]) + (1-bool2int(x[lx + i])) + (1-bool2int(y[ly + i])) + (1-bool2int(b[i+1])) <= 3 % /\ bool2int(b[i]) + bool2int(x[lx + i]) + bool2int(y[ly + i]) + (1-bool2int(b[i+1])) <= 3 %% This guy is dominated by the 1st one above but helps: % /\ bool2int(b[i]) + bool2int(x[lx + i]) + (1-bool2int(y[ly + i])) + (1-bool2int(b[i+1])) <= 3 ) /\ b[size+1] = (ux-lx <= uy-ly) % endif ; % forall(i in 0..size) ( % ( b[i] == ( x[lx + i] <= y[ly + i] ) ) % /\ % if i < size then % ( b[i] == ( x[lx + i] < y[ly + i] \/ b[i+1] % ) ) else true endif % ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/linear_scip/fzn_lex_lesseq_bool_reif.mzn000066400000000000000000000043241360574160400270400ustar00rootroot00000000000000predicate fzn_lex_lesseq_bool_reif(array[int] of var bool: x, array[int] of var bool: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = max(ux - lx, uy - ly), array[0..size+1] of var bool: b } % b[i] is true if the lexicographical order holds from position i on. in (c <-> b[0]) /\ forall(i in 0..size) ( ( b[i] -> ( x[lx + i] <= y[ly + i] ) ) /\ bool2int(b[i]) + bool2int(x[lx + i]) + (1-bool2int(y[ly + i])) <= 2 /\ ( b[i] -> ( x[lx + i] < y[ly + i] \/ b[i+1] ) ) /\ bool2int(b[i]) + (1-bool2int(x[lx + i])) + (1-bool2int(y[ly + i])) + (1-bool2int(b[i+1])) <= 3 /\ bool2int(b[i]) + bool2int(x[lx + i]) + bool2int(y[ly + i]) + (1-bool2int(b[i+1])) <= 3 /\ bool2int(b[i]) + bool2int(x[lx + i]) + (1-bool2int(y[ly + i])) + (1-bool2int(b[i+1])) <= 3 ) /\ b[size+1] = (ux-lx <= uy-ly) % endif ; predicate fzn_lex_lesseq_bool_imp(array[int] of var bool: x, array[int] of var bool: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = max(ux - lx, uy - ly), array[0..size+1] of var bool: b } % b[i] is true if the lexicographical order holds from position i on. in (c -> b[0]) /\ forall(i in 0..size) ( ( b[i] -> ( x[lx + i] <= y[ly + i] ) ) /\ bool2int(b[i]) + bool2int(x[lx + i]) + (1-bool2int(y[ly + i])) <= 2 /\ ( b[i] -> ( x[lx + i] < y[ly + i] \/ b[i+1] ) ) /\ bool2int(b[i]) + (1-bool2int(x[lx + i])) + (1-bool2int(y[ly + i])) + (1-bool2int(b[i+1])) <= 3 /\ bool2int(b[i]) + bool2int(x[lx + i]) + bool2int(y[ly + i]) + (1-bool2int(b[i+1])) <= 3 /\ bool2int(b[i]) + bool2int(x[lx + i]) + (1-bool2int(y[ly + i])) + (1-bool2int(b[i+1])) <= 3 ) /\ b[size+1] = (ux-lx <= uy-ly) ; libminizinc-2.4.2/share/minizinc/linear_scip/fzn_regular.mzn000066400000000000000000000107531360574160400243200ustar00rootroot00000000000000/** @group globals.extensional The sequence of values in array \a x (which must all be in the range 1..\a S) is accepted by the DFA of \a Q states with input 1..\a S and transition function \a d (which maps (1..\a Q, 1..\a S) -> 0..\a Q)) and initial state \a q0 (which must be in 1..\a Q) and accepting states \a F (which all must be in 1..\a Q). We reserve state 0 to be an always failing state. */ predicate fzn_regular(array[int] of var int: x, int: Q, int: S, array[int,int] of int: d, int: q0, set of int: F) = % my_trace(" regular: index_set(x)=" ++ show(index_set(x)) % ++ ", dom_array(x)=" ++ show(dom_array(x)) % ++ ", dom_array(a)=" ++ show(1..Q) % ++ "\n") /\ let { % If x has index set m..n-1, then a[m] holds the initial state % (q0), and a[i+1] holds the state we're in after processing % x[i]. If a[n] is in F, then we succeed (ie. accept the string). int: m = min(index_set(x)), int: n = max(index_set(x)) + 1, array[m..n] of var 1..Q: a, constraint a[m] = q0 /\ % Set a[0]. a[n] in F, % Check the final state is in F. constraint forall(i in index_set(x)) ( x[i] in 1..S % Do this in case it's a var. /\ %% trying to eliminate non-reachable states: let { set of int: va_R = { d[va, vx] | va in dom(a[i]), vx in dom(x[i]) } diff { 0 } %% Bug in MZN 2.0.4 } in a[i+1] in va_R ) } in let { constraint forall(i in [n-i | i in 1..length(x)]) ( a[i] in { va | va in dom(a[i]) where exists(vx in dom(x[i]))(d[va, vx] in dom(a[i+1])) } /\ x[i] in { vx | vx in dom(x[i]) where exists(va in dom(a[i]))(d[va, vx] in dom(a[i+1])) } ) } in forall(i in index_set(x)) ( let { set of int: va_R = { d[va, vx] | va in dom(a[i]), vx in dom(x[i]) } diff { 0 } %% Bug in MZN 2.0.4 } in % my_trace(" S" ++ show(i) % ++ ": dom(a[i])=" ++ show(dom(a[i])) % ++ ", va_R="++show(va_R) % ++ ", index_set_2of2(eq_a) diff va_R=" ++ show(index_set_2of2(eq_a) diff va_R) % ++ ", dom(a[i+1])=" ++ show(dom(a[i+1])) % ) /\ a[i+1] in va_R %/\ a[i+1] in min(va_R)..max(va_R) ) % /\ my_trace(" regular -- domains after prop: index_set(x)=" ++ show(index_set(x)) % ++ ", dom_array(x)=" ++ show(dom_array(x)) % ++ ", dom_array(a)=" ++ show(dom_array(a)) % ++ "\n") % /\ my_trace("\n") /\ let { array[int, int] of var int: eq_a=eq_encode(a), array[int, int] of var int: eq_x=eq_encode(x), } in forall(i in index_set(x)) ( % a[i+1] = d[a[i], x[i]] % Determine a[i+1]. if card(dom(a[i]))*card(dom(x[i])) > nMZN__UnarySizeMax_1step_regular then %% Implication decomposition: forall(va in dom(a[i]), vx in dom(x[i]))( if d[va, vx] in dom(a[i+1]) then eq_a[i+1, d[va, vx]] >= eq_a[i, va] + eq_x[i, vx] - 1 %% The only-if part of conj else 1 >= eq_a[i, va] + eq_x[i, vx] endif ) else %% Network-flow decomposition: %% {regularIP07} M.-C. C{\^o}t{\'e}, B.~Gendron, and L.-M. Rousseau. %% \newblock Modeling the regular constraint with integer programming. let { % array[int, int] of set of int: VX_a12 = %% set of x for given a1 that produce a2 % array2d(1..S, 1..Q, [ { vx | vx in 1..S where d[va1, vx]==va2 } | va1 in dom(a[i]), va2 in dom(a[i+1]) ]); array[int, int] of var int: ppAX = eq_encode(a[i], x[i]); } in forall (va2 in dom(a[i+1])) ( eq_a[i+1, va2] = sum(va1 in dom(a[i]), vx in dom(x[i]) where d[va1, vx]==va2) (ppAX[va1, vx]) ) /\ forall(va1 in dom(a[i]), vx in dom(x[i]))( if not (d[va1, vx] in dom(a[i+1])) then ppAX[va1, vx] == 0 else true endif ) endif ); libminizinc-2.4.2/share/minizinc/linear_scip/fzn_sliding_sum.mzn000066400000000000000000000010561360574160400251700ustar00rootroot00000000000000/** @group globals Requires that in each subsequence \a vs[\p i], ..., \a vs[\p i + \a seq - 1] the sum of the values belongs to the interval [\a low, \a up]. */ predicate fzn_sliding_sum(int: low, int: up, int: seq, array[int] of var int: vs) = let { int: lx = min(index_set(vs)), int: ux = max(index_set(vs)), } in forall (i in lx .. ux - seq + 1) ( let { var int: sum_of_l = sum(j in i..i + seq - 1) (vs[j]) } in low <= sum_of_l /\ sum_of_l <= up ); libminizinc-2.4.2/share/minizinc/linear_scip/fzn_subcircuit.mzn000066400000000000000000000042251360574160400250300ustar00rootroot00000000000000include "alldifferent.mzn"; /** @group globals Constrains the elements of \a x to define a subcircuit where \a x[\p i] = \p j means that \p j is the successor of \p i and \a x[\p i] = \p i means that \p i is not in the circuit. */ %% Linear version predicate fzn_subcircuit(array[int] of var int: x) = let { set of int: S = index_set(x), int: l = min(S), int: u = max(S), int: n = card(S), array[S] of var 1..n: order, array[S] of var bool: ins = array1d(S,[ x[i] != i | i in S]), var l..u+1: firstin = min([ u+1 + bool2int(ins[i])*(i-u-1) | i in S]), %% ... var S: lastin, var bool: empty = (firstin == u+1), } in alldifferent(x) /\ % NO alldifferent(order) /\ % If the subcircuit is empty then each node points at itself. % (empty <-> forall(i in S)(not ins[i])) /\ % If the subcircuit is non-empty then order numbers the subcircuit. % ((not empty) <-> %% Another way to express minimum. % forall(i in l..u+1)( % i==firstin <-> ins[i] % /\ forall(j in S where j firstin /\ % The lastin node points at firstin. x[lastin] = firstin /\ % And both are in ins[lastin] /\ ins[firstin] /\ % The successor of each node except where it is firstin is % numbered one more than the predecessor. % forall(i in S) ( % (ins[i] /\ x[i] != firstin) -> order[x[i]] = order[i] + 1 % ) /\ %%% MTZ model. Note that INTEGER order vars seem better!: forall (i,j in S where i!=j) ( order[i] - order[j] + n*bool2int( x[i]==j /\ i!=lastin ) % + (n-2)*bool2int(x[j]==i) %% the Desrochers & Laporte '91 term <= n-1 ) /\ % Each node that is not in is numbered after the lastin node. forall(i in S) ( true % (not ins[i]) <-> (n == order[i]) ) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/linear_scip/fzn_table_int.mzn000066400000000000000000000013471360574160400246170ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % A 'table' constraint table(x, T) represents the constraint x in T where we % consider each row in T to be a tuple and T as a set of tuples. % % Linear version. % % See also the equality encoding of the 'element' constraint. %-----------------------------------------------------------------------------% predicate fzn_table_int(array[int] of var int: x, array[int, int] of int: t) = let { set of int: it = index_set_1of2(t), array[it] of var 0..1: lambda } in sum(lambda) = 1 /\ forall(j in index_set(x))( sum(i in it)( t[i,j]*lambda[i] ) = x[j] ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/linear_scip/options.mzn000066400000000000000000000166601360574160400235000ustar00rootroot00000000000000/* % Controls % */ %-----------------------------------------------------------------------------% %---------- USER and LAZY CUTS -----------------------------------------------% /* PLEASE NOTE: If you export FZN file with lazy_constraint/user_cut annotations, their declarations are not exported currently (as of 7.11.17). WORKAROUND: when solving that fzn, add -G linear, e.g., as follows: mzn-cplex -G linear model.fzn * For Gurobi, the constraints marked as MIP_cut and/or MIP_lazy are added * into the overall model and marked with the foll values of Lazy attribute: * ::MIP_lazy 1 * ::MIP_cut ::MIP_lazy 2 * ::MIP_cut 3 */ ann: user_cut; ann: lazy_constraint; %%% comment away the below assignments (leaving, e.g., ann: MIP_cut;) to have them as normal constraints %%% In particular, they may be used by redundant_constraint() and symmetry_breaking_constraint(), see redefs-2.0.2.mzn ann: MIP_cut = user_cut; %% MIP_cut: make sure no feasible solutions are cut off %% -- seems better on average but in CPLEX, wrong LB e.g. on carpet-cutting ann: MIP_lazy = lazy_constraint; %-----------------------------------------------------------------------------% opt bool: fIndConstr; bool: fMZN__UseIndicators = %% Pass on indicator constraints if absent( fIndConstr ) then false else deopt( fIndConstr ) endif; %% CPLEX 12.6.2 Concert: reifs give wrong result on 2012/amaze, so using implications only %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Subtour elimination in circuit %%%%%%%%%%%%%%%%%%%%%%%%%%%%% % --------------------------------------------------------------------------------------- % opt int: nSECcuts; %% 0,1: use MTZ formulation int: nMZN__fSECcuts = %% 1,2: pass on circuit constraints to the MIP_solverinstance's cut gen if absent( nSECcuts ) then 0 else deopt( nSECcuts ) endif; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% MIPdomains %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % --------------------------------------------------------------------------------------- % %% Paper: % Belov, Stuckey, Tack, Wallace. Improved Linearization of Constraint Programming Models. CP 2016 Proceedings. %%% The below option enables translation of domain constraints into the ...POST predicates. %%% The code in MIPdomains.cpp processes them and also non-contiguous domains %%% (only-range-domains is then standardly off). MIPdomains.cpp needs all the required %%% __POST predicates to be declared to kick in. opt bool: fMIPDomains; %% unified decomposition constraints (...__POST) to FlatZinc opt bool: fMIPdomains; %% Can be defined from cmdline: -D "fMIPdomains=false" bool: fPostprocessDomains = %% True to pass all domain-related if absent( fMIPdomains ) /\ absent( fMIPDomains ) then true elseif not absent( fMIPdomains ) then deopt( fMIPdomains ) else deopt( fMIPDomains ) endif; opt bool: fMIPdomAux; bool: fPostproDom_AUX = %% Specialized for aux_ constr if absent( fMIPdomAux ) then false else deopt( fMIPdomAux ) endif; opt bool: fMIPdomDiff; bool: fPostproDom_DIFF = %% Specialized for differences: x z=x-y<0 if absent( fMIPdomDiff ) then false %% seems best for Gurobi, worse for CBC else deopt( fMIPdomDiff ) endif; mzn_opt_only_range_domains = not fPostprocessDomains; %% currently unused %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Avoid creating new int vars %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % --------------------------------------------------------------------------------------- % opt bool: fAvoidNewInts; bool: fAvoidNI = %% Actually this is only for ..._lin_..., not for just x-y if absent( fAvoidNewInts ) then false else deopt( fAvoidNewInts ) endif; opt bool: fNewVarsInAuxEq; bool: fAuxIntEqOLD00 = if absent(fNewVarsInAuxEq) then false else deopt(fNewVarsInAuxEq) endif; bool: fAuxFloatEqOLD00 = if absent(fNewVarsInAuxEq) then false else deopt(fNewVarsInAuxEq) endif; %%%%%%%%%%%%%%%%%%%%% Redundant constraints ---------------------------------------------- % bool: fMZN__IgnoreRedundantCumulative=false; %% NOT WORKING NOW, use redefs_2.0.2.mzn: %%%%% bool: fMZN__IgnoreAllUserRedundant=false; %% ignore all user-spec redundant constr %%%%%%%%%%%%%%%%%%%%% Element, minimuum convex hull --------------------------------------- % opt bool: fXBZCuts01; %% orders 0, 1 opt bool: fXBZCutGen; %% only works if Cuts01 bool: fElementCutsXZ=false; %% Use simple XZ & XZB cuts for element bool: fElementCutsXZB = if absent(fXBZCuts01) then false else deopt(fXBZCuts01) endif; bool: fMinimumCutsXZ=false; %% Use simple XZ & XZB cuts for minimum bool: fMinimumCutsXZB = if absent(fXBZCuts01) then false else deopt(fXBZCuts01) endif; bool: fUseXBZCutGen = if absent(fXBZCutGen) then false else deopt(fXBZCutGen) endif; % ----------------------------------------------------------------------------------------- % bool: fIntTimesBool=true; %% Special handling of multiplication with a boolean(*const) %-----------------------------------------------------------------------------% % If not postprocessing domains: For unary encoding: maximal domain length to invoke it int: nMZN__UnarySizeMax_intTimes=20; int: nMZN__UnarySizeMax_cumul=2000; int: nMZN__UnarySizeMax_1step_regular=20000; %% network-flow decomp in the regular constraint int: nMZN__UnaryLenMin__ALL=1; %% can be used by the indiv. cases int: nMZN__UnaryLenMax__ALL=2000; %% can be used by the indiv. cases % Some more detailed parameters int: nMZN__UnaryLenMin_leq = 1; int: nMZN__UnaryLenMin_neq = nMZN__UnaryLenMin__ALL; int: nMZN__UnaryLenMin_eq = nMZN__UnaryLenMin__ALL; int: nMZN__UnaryLenMax_leq = -1; int: nMZN__UnaryLenMax_neq = nMZN__UnaryLenMax__ALL; int: nMZN__UnaryLenMax_eq = nMZN__UnaryLenMax__ALL; int: nMZN__UnaryLenMax_setIn = nMZN__UnaryLenMax__ALL; int: nMZN__UnaryLenMax_setInReif = nMZN__UnaryLenMax__ALL; %-----------------------------------------------------------------------------% % Strict inequality % The relative epsilon %%% Has the problem that when relating to upper bound of various differences, %%% getting different absolute eps...? %% float: float_lt_EPS_coef__ = 1e-03; ABANDONED 12.4.18 due to #207 %%% Absolute one, used everywhere %%% Might make no sense for floats with smaller domains etc. opt float: float_EPS; float: float_lt_EPS = if absent( float_EPS ) then 1e-6 else deopt( float_EPS ) endif; %-----------------------------------------------------------------------------% %%% Set =true to PRINT TRACING messages for some constraints: opt bool: fMIPTrace; bool: mzn__my_trace_on = if absent( fMIPTrace ) then false else deopt( fMIPTrace ) endif; test my_trace(string: msg) ::promise_total = if mzn__my_trace_on then trace(msg) else true endif; test my_trace(string: msg, bool: bb) ::promise_total = if mzn__my_trace_on then trace(msg, bb) else bb endif; function var bool: my_trace(string: msg, var bool: bb) ::promise_total = if mzn__my_trace_on then trace(msg, bb) else bb endif; %%% Set =true to PRINT TRACING messages for the currently debugged constraints: opt bool: fMIPTraceDBG; bool: mzn__my_trace__DBG_on = if absent( fMIPTraceDBG ) then false else deopt( fMIPTraceDBG ) endif; test my_trace__DBG(string: msg) ::promise_total = if mzn__my_trace__DBG_on then trace(msg) else true endif; libminizinc-2.4.2/share/minizinc/linear_scip/redefinitions-2.0.2.mzn000066400000000000000000000022661360574160400253010ustar00rootroot00000000000000% This file contains redefinitions of standard builtins for version 2.0.2 % that can be overridden by solvers. predicate symmetry_breaking_constraint(var bool: b) = (b) %:: MIP_lazy %:: MIP_cut %% MIP_cut wrong in CPLEX 12.6.3 %% Symm breaking as lazy is 1% better in Gurobi 6.5.2 on the Challenges 2012-2015 %% But caused a bug in 7.5.1 - switched off %% true %% TO omit all symmetry_breaking_constraint's ; %% Make sure no feasible solutions are cut off: predicate redundant_constraint(var bool: b) = (b) %:: MIP_cut % true %% To omit all redundant_constraint's ; %% Linearized element: just call without shifting predicate array_var_bool_element_nonshifted(var int: idx, array[int] of var bool: x, var bool: c) = array_var_bool_element(idx,x,c); predicate array_var_int_element_nonshifted(var int: idx, array[int] of var int: x, var int: c) = array_var_int_element(idx,x,c); predicate array_var_float_element_nonshifted(var int: idx, array[int] of var float: x, var float: c) = array_var_float_element(idx,x,c); predicate array_var_set_element_nonshifted(var int: idx, array[int] of var set of int: x, var set of int: c) = array_var_set_element(idx,x,c); libminizinc-2.4.2/share/minizinc/linear_scip/redefinitions-2.0.mzn000066400000000000000000000027471360574160400251450ustar00rootroot00000000000000predicate bool_clause_reif(array[int] of var bool: p, array[int] of var bool: n, var bool: c) = c = ( sum(i in index_set(p))( bool2int(p[i]) ) - sum(i in index_set(n))( bool2int(n[i]) ) + length(n) >= 1 ); predicate array_float_minimum(var float: m, array[int] of var float: x) = if false then array_float_minimum__IND(m, x) %% transfer to Concert because of prepro else array_float_minimum_I( m, [ x[i] | i in index_set(x)]) endif; predicate array_float_maximum(var float: m, array[int] of var float: x) = if false then array_float_maximum__IND(m, x) else array_float_minimum_I(-m, [-x[i] | i in index_set(x)]) endif; predicate array_int_minimum(var int: m, array[int] of var int: x) = if false then array_int_minimum__IND(m, x) else array_float_minimum_I( int2float(m), [ int2float(x[i]) | i in index_set(x)]) endif; predicate array_int_maximum(var int: m, array[int] of var int: x) = if false then array_int_maximum__IND(m, x) else array_float_minimum_I(-int2float(m), [-int2float(x[i]) | i in index_set(x)]) endif; % predicate array_int_maximum__OLD_SYMMETRIES(var int: m, array[int] of var int: x) = % let { int: l = min(index_set(x)), % int: u = max(index_set(x)), % int: ly = lb_array(x), % int: uy = ub_array(x), % array[l..u] of var ly..uy: y } in % y[l] = x[l] /\ % m = y[u] /\ % forall (i in l+1 .. u) ( y[i] == max(x[i],y[i-1]) ); libminizinc-2.4.2/share/minizinc/linear_scip/redefinitions-2.2.1.mzn000066400000000000000000000004001360574160400252660ustar00rootroot00000000000000% This file contains redefinitions of standard builtins for version 2.2.1 % that can be overridden by solvers. /** @group flatzinc.int Constrains \a z = \(\a x ^ {\a y}\) */ predicate int_pow_fixed(var int: x, int: y, var int: z) = int_pow( x, y, z ); libminizinc-2.4.2/share/minizinc/linear_scip/redefinitions.mzn000066400000000000000000000606031360574160400246430ustar00rootroot00000000000000/* % FlatZinc built-in redefinitions for linear solvers. % % AUTHORS % Sebastian Brand % Gleb Belov (2015-) % cf. Belov, Stuckey, Tack, Wallace. Improved Linearization of Constraint Programming Models. CP 2016. */ %----------------------------- BOOL2INT --------------------------------% function var bool: reverse_map(var int: x) = (x==1); function bool: reverse_map(int: x) = (x==1); predicate mzn_reverse_map_var(var bool: b) = let { var int: x = bool2int(b) } in true; function var int: bool2int(var bool: x) :: promise_total = let { var 0..1: b2i; constraint (x = reverse_map(b2i)) ::is_reverse_map ; } in b2i; predicate bool_eq(var bool: x, var bool: y) = %% trace(" bool_eq: \(x), \(y) \n") /\ bool2int(x)==bool2int(y); %---------------------------- BASIC (HALF)REIFS -----------------------------% include "options.mzn"; include "redefs_bool_reifs.mzn"; include "redefs_bool_imp.mzn"; include "domain_encodings.mzn"; include "redefs_lin_reifs.mzn"; include "redefs_lin_imp.mzn"; include "redefs_lin_halfreifs.mzn"; include "nosets.mzn"; %% For set_le, set_lt ... Usind std/nosets %% as long as the linearization is good. %-----------------------------------------------------------------------------% % Strict inequality % Uncomment the following redefinition for FlatZinc MIP solver interfaces that % do not support strict inequality. Note that it does not preserve equivalence % (some solutions of the original problem may become invalid). predicate float_lt(var float: x, var float: y) = % (x - y) <= (-float_lt_EPS_coef__)*max(abs(ub(x - y)), abs(ub(y-x))); x <= y - float_lt_EPS; predicate float_lin_lt(array[int] of float: c, array[int] of var float: x, float: d) = float_lt(sum(i in index_set(x))( c[i]*x[i] ), d); %-----------------------------------------------------------------------------% % Minimum, maximum, absolute value % Use unary as well? TODO predicate int_abs(var int: x, var int: z) = %% The simplifications seem worse on league.mzn model90-18-20.dzn: %% but the .lp seem to differ just by order...?? TODO if lb(x)>=0 then z==x elseif ub(x)<=0 then z==-x else let { var bool: p } in z >= x /\ z >= -x /\ z >= 0 /\ % This is just for preprocessor z <= max([ub(x), -lb(x)]) /\ % And this % z <= x \/ z <= -x %% simple aux_int_le_if_1(z, x, p) /\ %% even simpler aux_int_le_if_0(z, -x, p) /\ int_le_reif(0, x, p) % with reifs %int_eq_reif(z, x, p) /\ %int_eq_reif(z, -x, not p) endif ; predicate int_min(var int: x, var int: y, var int: z) = array_int_minimum(z, [x, y]); predicate int_max(var int: x, var int: y, var int: z) = array_int_maximum(z, [x, y]); predicate float_abs(var float: x, var float: z) = if lb(x)>=0.0 then z==x elseif ub(x)<=0.0 then z==-x else let { var bool: p } in z >= x /\ z >= -x /\ z >= 0.0 /\ % This is just for preprocessor z <= max([ub(x), -lb(x)]) /\ % And this % z <= x \/ z <= -x aux_float_le_if_1(z, x, (p)) /\ aux_float_le_if_0(z, -x, (p)) % /\ % float_le_reif(0.0, x, p) % with reifs - no point for floats? TODO % float_eq_reif(z, x, p) /\ % float_eq_reif(z, -x, not p) endif; predicate float_min(var float: x, var float: y, var float: z) = array_float_minimum(z, [x, y]); predicate float_max(var float: x, var float: y, var float: z) = array_float_maximum(z, [x, y]); predicate array_float_minimum_I(var float: m, array[int] of var float: x) = let { int: n = length(x), constraint assert(1 == min(index_set(x)), " array_float_minimum_I: argument indexed not from 1??"), int: iMinUB = arg_min([ub(x[i]) | i in 1..n]), float: MinUB = ub(x[iMinUB]), set of int: sLBLess = { i | i in 1..n where lb(x[i])0 then sLBLess else sLBLess union { iMinUB } endif, } in if 1==card(sActive) then m == x[min(sActive)] else let { array[1..n] of var int: p = [ if i in sActive then let { var 0..1: pi } in pi else 0 endif | i in 1..n ], constraint 1==sum(p), constraint m >= lb_array(x), constraint m <= MinUB, } in forall (i in index_set(x)) ( if i in sActive %% for at least 1 element then m<=x[i] /\ aux_float_ge_if_1(m, x[i], p[i]) else true endif ) %% -- exclude too big x[i] /\ if card(sActive)>1 /\ fMinimumCutsXZ then let { array[int] of float: AL = [ lb(x[i]) | i in 1..n], array[int] of int: srt = sort_by([i | i in 1..n], AL), %indices of lb in sorted order array[int] of float: AL_srt = [AL[srt[i]] | i in 1..n], array[int] of float: AU_srt = [ub(x[srt[i]]) | i in 1..n], array[int] of float: AM_srt = AL_srt ++ [MinUB] %% -- these are z-levels of extreme points } in forall (i in 2..n+1 where AM_srt[i]<=MinUB /\ %% this is a new "start level" AM_srt[i]!=AM_srt[i-1] )( %% and would produce a new cut m >= AM_srt[i] - sum(j in 1..i-1 where AL_srt[j]1 /\ fMinimumCutsXZB then array_var_float_element__XBZ_lb([ -x[i] | i in sActive ], [ p[i] | i in sActive ], -m) :: MIP_cut else true endif endif ; %-----------------------------------------------------------------------------% % Multiplication and division predicate int_div(var int: x, var int: y, var int: q) = q == aux_int_division_modulo_fn(x,y)[1]; predicate int_mod(var int: x, var int: y, var int: r) = r == aux_int_division_modulo_fn(x,y)[2]; function array[int] of var int: aux_int_division_modulo_fn(var int: x, var int: y) = let { %% Domain of q set of int: dom_q = if lb(y)*ub(y)>0 then let { set of int: EP = { ub(x) div ub(y), ub(x) div lb(y), lb(x) div ub(y), lb(x) div lb(y) }, } in min(EP)..max(EP) else let { int: mm = max( abs(lb(x)), abs(ub(x)) ), } in -mm..mm %% TODO case when -1 or 1 not in dom(x) endif, var dom_q: q; int: by = max(abs(lb(y)), abs(ub(y))); var -by+1..by-1: r; constraint x = y * q + r, constraint 0 <= x -> 0 <= r, %% which is 0 > x \/ 0 <= r constraint x < 0 -> r <= 0, %% which is x >= 0 \/ r <= 0 % abs(r) < abs(y) var 1.. max(abs(lb(y)), abs(ub(y))): w = abs(y), constraint w > r /\ w > -r, } in [ q, r ]; %% Can also have int_times(var float, var int) ......... TODO predicate int_times(var int: x, var int: y, var int: z) = if is_fixed(x) then z==fix(x)*y %%%%% Need to use fix() otherwise added to map & nothing happens elseif is_fixed(y) then z==x*fix(y) else if 0..1==dom(x) /\ 0..1==dom(y) then bool_and__INT(x,y,z) elseif card(dom(x))==2 /\ card(dom(y))==2 /\ 0 in dom(x) /\ 0 in dom(y) then let { var 0..1: xn; var 0..1: yn; var 0..1: zn; constraint x=xn*max(dom(x) diff {0}); constraint y=yn*max(dom(y) diff {0}); constraint z=zn*max(dom(x) diff {0})*max(dom(y) diff {0}); } in bool_and__INT(xn,yn,zn) elseif card(dom(x)) * card(dom(y)) > nMZN__UnarySizeMax_intTimes \/ ( fIntTimesBool /\ ( %% Peter's idea for *bool. More optimal but worse values on carpet cutting. (card(dom(x))==2 /\ 0 in dom(x)) \/ (card(dom(y))==2 /\ 0 in dom(y)) ) ) then %% PARAM %% ALSO NO POINT IF <=4. TODO if card(dom(x)) > card(dom(y)) \/ ( card(dom(x))==card(dom(y)) /\ 0 in dom(y) /\ not (0 in dom(x)) ) then int_times(y,x,z) else let { set of int: s = lb(x)..ub(x), set of int: r = {lb(x)*lb(y), lb(x)*ub(y), ub(x)*lb(y), ub(x)*ub(y)}, array[s] of var min(r)..max(r): ady = array1d(s, [ if d in dom(x) then d*y else min(r) endif | d in s ]) } in ady[x] = z %% use element() endif else int_times_unary(x, { }, y, z) endif endif; %% domx__ can be used to narrow domain... NOT IMPL. predicate int_times_unary(var int: x, set of int: domx__, var int: y, var int: z) = let { set of int: r = {lb(x)*lb(y), lb(x)*ub(y), ub(x)*lb(y), ub(x)*ub(y)}, %% set of int: domx = if card(domx__)>0 then domx__ else dom(x) endif, array[int, int] of var int: pp=eq_encode(x, y) } in z>=min(r) /\ z<=max(r) /\ z==sum(i in index_set_1of2(pp), j in index_set_2of2(pp)) (i * j * pp[i, j]) /\ forall(i in index_set_1of2(pp), j in index_set_2of2(pp) where not ((i*j) in dom(z)) )(pp[i, j]==0) ; predicate int_times_unary__NOFN(var int: x, set of int: domx__, var int: y, var int: z) = let { set of int: r = {lb(x)*lb(y), lb(x)*ub(y), ub(x)*lb(y), ub(x)*ub(y)}, %% set of int: domx = if card(domx__)>0 then domx__ else dom(x) endif, array[int] of var int: pX = eq_encode(x), array[int] of var int: pY = eq_encode(y), array[int] of int: valX = [ v | v in index_set(pX) ], %% NOT domx. array[int] of int: valY = [ v | v in index_set(pY) ], %% -- according to eq_encode! array[index_set(valX), index_set(valY)] of var 0..1: pp %% both dim 1.. } in if is_fixed(x) \/ is_fixed(y) then z==x*y else z>=min(r) /\ z<=max(r) /\ sum(pp)==1 /\ z==sum(i in index_set(valX), j in index_set(valY)) (valX[i] * valY[j] * pp[i, j]) /\ forall(i in index_set(valX)) ( pX[valX[i]] == sum(j in index_set(valY))( pp[i, j] ) ) /\ forall(j in index_set(valY)) ( pY[valY[j]] == sum(i in index_set(valX))( pp[i, j] ) ) endif; predicate float_times(var float: a, var float: b, var float: c) = abort("Unable to create linear formulation for the `float_times` constraint. This model instance cannot be solved using a linear solver."); %%%Define int_pow predicate int_pow( var int: x, var int: y, var int: r ) = let { array[ int, int ] of int: x2y = array2d( lb(x)..ub(x), lb(y)..ub(y), [ pow( X, Y ) | X in lb(x)..ub(x), Y in lb(y)..ub(y) ] ) } in r == x2y[ x, y ]; %%% Adding a version returning float for efficiency /** @group builtins.arithmetic Return \(\a x ^ {\a y}\) */ function var float: pow_float(var int: x, var int: y) = let { int: yy = if is_fixed(y) then fix(y) else -1 endif; } in if yy = 0 then 1 elseif yy = 1 then x else let { var float: r ::is_defined_var; constraint int_pow_float(x,y,r) ::defines_var(r); } in r endif; %%%Define int_pow_float predicate int_pow_float( var int: x, var int: y, var float: r ) = let { array[ int, int ] of float: x2y = array2d( lb(x)..ub(x), lb(y)..ub(y), [ pow( X, Y ) | X in lb(x)..ub(x), Y in lb(y)..ub(y) ] ) } in r == x2y[ x, y ]; %-----------------------------------------------------------------------------% % Array 'element' constraints predicate array_bool_element(var int: x, array[int] of bool: a, var bool: z) = array_int_element(x, arrayXd(a, [bool2int(a[i]) | i in index_set(a)]), bool2int(z)); predicate array_var_bool_element(var int: x, array[int] of var bool: a, var bool: z) = array_var_int_element(x, arrayXd(a, [bool2int(a[i]) | i in index_set(a)]), bool2int(z)); predicate array_int_element(var int: x, array[int] of int: a, var int: z) = let { constraint x in { i | i in index_set(a) where a[i] in dom(z) }, } in array_float_element(x, arrayXd(a, [int2float(a[i]) | i in index_set(a)]), int2float(z)); predicate array_var_int_element(var int: x, array[int] of var int: a, var int: z) = let { constraint x in { i | i in index_set(a) where 0 < card(dom(a[i]) intersect dom(z)) }, } in %%%% Relate to the float version: array_var_float_element(x, arrayXd(a, [int2float(a[i]) | i in index_set(a)]), int2float(z)); %%%% Simplistic version: %%%% Complete binarization: MEMORY FULL. Need exact domains & sparse encoding predicate array_float_element(var int: i00, array[int] of float: a, var float: z) = let { set of int: ix = index_set(a), constraint i00 in { i | i in ix where a[i]>=lb(z) /\ a[i]<=ub(z) }, } in %%% Finish domain before dMin/dMax let { float: dMin = min(i in dom(i00))(a[i]), float: dMax = max(i in dom(i00))(a[i]), } in if dMin==dMax then z==dMin else z >= dMin /\ z <= dMax /\ let { int: nUBi00 = max(dom(i00)), int: nLBi00 = min(dom(i00)), float: nMinDist = min(i in nLBi00 .. nUBi00-1)(a[i+1]-a[i]), float: nMaxDist = max(i in nLBi00 .. nUBi00-1)(a[i+1]-a[i]), } in if nMinDist == nMaxDist then %% The linear case z == a[nLBi00] + nMinDist*(i00-nLBi00) else let { array[int] of var int: p = eq_encode(i00) %% this needs i00 in ix } in assert(dom(i00) subset index_set(p), "", true) /\ sum(i in dom(i00))( a[i] * int2float(p[i]) ) == z %% add more hull? endif endif; predicate array_var_float_element(var int: i00, array[int] of var float: a, var float: z) = let { set of int: ix = index_set(a), constraint i00 in { i | i in ix where lb(a[i])<=ub(z) /\ ub(a[i])>=lb(z) }, } in %% finish domain first let { float: minLB=min(i in dom(i00))(lb(a[i])), float: maxUB=max(i in dom(i00))(ub(a[i])) } in if minLB==maxUB then z==minLB else z >= minLB /\ z <= maxUB /\ if {0,1}==dom(i00) /*ub(i00)-lb(i00)==1*/ /*2==card( dom( i00 ) )*/ then aux_float_eq_if_1(z, a[lb(i00)], (ub(i00)-i00)) /\ aux_float_eq_if_1(z, a[ub(i00)], (i00-lb(i00))) else let { array[int] of var int: p = eq_encode(i00), } in assert(dom(i00) subset index_set(p), "", true) /\ %%% The convexified bounds seem slow for ^2 and ^3 equations: % sum(i in dom(i01))( lb(a[i]) * int2float(p[i]) ) <= z /\ %% convexify lower bounds % sum(i in dom(i01))( ub(a[i]) * int2float(p[i]) ) >= z /\ %% convexify upper bounds forall (i in dom(i00))( aux_float_eq_if_1(z, a[i], p[i]) ) %% Cuts: /\ if fElementCutsXZ then array_var_float_element__ROOF([ a[i] | i in dom(i00) ], z) :: MIP_cut %% these 2 better as user cuts - too slow /\ array_var_float_element__ROOF([ -a[i] | i in dom(i00) ], -z) :: MIP_cut %% or even skip them else true endif /\ if fElementCutsXZB then array_var_float_element__XBZ_lb([ a[i] | i in dom(i00) ], [ p[i] | i in dom(i00) ], z) :: MIP_cut /\ array_var_float_element__XBZ_lb([ -a[i] | i in dom(i00) ], [ p[i] | i in dom(i00) ], -z) :: MIP_cut else true endif endif endif; %%% Facets on the upper surface of the z-a polytope %%% Possible parameter: maximal number of first cuts taken only predicate array_var_float_element__ROOF(array[int] of var float: a, var float: z) = let { set of int: ix = index_set(a), int: n = length(a), array[int] of float: AU = [ ub(a[i]) | i in 1..n], array[int] of int: srt_ub = sort_by([i | i in 1..n], AU), %indices of ub sorted up array[int] of float: AU_srt_ub = [ub(a[srt_ub[i]]) | i in 1..n], array[int] of float: AL_srt_ub = [lb(a[srt_ub[i]]) | i in 1..n], array[int] of float: MaxLBFrom = [ max(j in index_set(AL_srt_ub) where j>=i)(AL_srt_ub[j]) | i in 1..n ], %% direct, O(n^2) array[int] of float: ULB = [ if 1==i then MaxLBFrom[1] else max([AU_srt_ub[i-1], MaxLBFrom[i]]) endif | i in 1..n ] } in %%% "ROOF" forall (i in 1..n where if i==n then true else ULB[i]!=ULB[i+1] endif %% not the same base bound )( z <= ULB[i] + sum( j in i..n where AU_srt_ub[i] != AL_srt_ub[i] ) %% not a const ( (AU_srt_ub[j]-ULB[i]) * (a[srt_ub[j]]-AL_srt_ub[j]) / (AU_srt_ub[j]-AL_srt_ub[j]) ) ) ; predicate array_var_float_element__XBZ_lb(array[int] of var float: x, array[int] of var int: b, var float: z) = if fUseXBZCutGen then array_var_float_element__XBZ_lb__cutgen(x, b, z) :: MIP_cut else %% Adding some cuts a priori, also to make solver extract the variables let { int: i1 = min(index_set(x)) } in (z <= sum(i in index_set(x))(ub(x[i]) * b[i])) %:: MIP_cut -- does not work to put them here TODO /\ forall(i in index_set(x) intersect i1..(i1+19)) %% otherwise too many on amaze2 ( assert(lb(x[i]) == -ub(-x[i]) /\ ub(x[i]) == -lb(-x[i]), " negated var's bounds should swap " ) /\ z <= x[i] + sum(j in index_set(x) where i!=j)((ub(x[j])-lb(x[i]))*b[j])) %:: MIP_cut %% (ub_j-lb_i) * b_j /\ forall(i in index_set(x) intersect i1..(i1+19)) ( z <= ub(x[i])*b[i] + sum(j in index_set(x) where i!=j)(x[j]+lb(x[j])*(b[j]-1)) ) %:: MIP_cut /\ (z <= sum(i in index_set(x))(x[i] + lb(x[i]) * (b[i]-1))) %:: MIP_cut endif; %-----------------------------------------------------------------------------% % Set constraints %% ----------------------------------------------- (NO) SETS ---------------------------------------------- % XXX only for a fixed set here, general see below. % Normally not called because all plugged into the domain. % Might be called instead of set_in(x, var set of int s) if s gets fixed? predicate set_in(var int: x, set of int: s__) = let { set of int: s = if has_bounds(x) then s__ intersect dom(x) else s__ endif, constraint min(s) <= x, constraint x <= max(s), } in if s = min(s)..max(s) then true elseif fPostprocessDomains then set_in__POST(x, s) else %% Update eq_encode let { array[int] of var int: p = eq_encode(x); } in forall(i in index_set(p) diff s)(p[i]==0) % let { % array[int] of int: sL = [ e | e in s where not (e - 1 in s) ]; % array[int] of int: sR = [ e | e in s where not (e + 1 in s) ]; % array [index_set(sR)] of var 0..1: B; % constraint assert(length(sR)==length(sL), "N of lb and ub of sub-intervals of a set should be equal"); % } in % sum(B) = 1 %% use indicators % /\ % x >= sum(i in index_set(sL))(B[i]*sL[i]) % /\ % x <= sum(i in index_set(sR))(B[i]*sR[i]) endif; %%% for a fixed set predicate set_in_reif(var int: x, set of int: s__, var bool: b) = if is_fixed(b) then if fix(b) then x in s__ else x in dom(x) diff s__ endif elseif has_bounds(x) /\ not (s__ subset dom(x)) then b <-> x in s__ intersect dom(x) %% Use CSE else let { set of int: s = if has_bounds(x) then s__ intersect dom(x) else s__ endif, } in ( if dom(x) subset s then b==true elseif card(dom(x) intersect s)==0 then b==false elseif fPostprocessDomains then set_in_reif__POST(x, s, b) %% Bad. Very much so for CBC. 27.06.2019: elseif s == min(s)..max(s) then %% b <-> (min(s) <= x /\ x <= max(s)) else if card(dom(x))<=nMZN__UnaryLenMax_setInReif then %% PARAM TODO let { array[int] of var int: p = eq_encode(x); } in sum(i in s intersect dom(x))(p[i]) == bool2int(b) else bool2int(b) == fVarInBigSetOfInt(x, s) endif endif ) endif; % Alternative predicate alt_set_in_reif(var int: x, set of int: s, var bool: b) = b <-> exists(i in 1..length([ 0 | e in s where not (e - 1 in s) ]))( let { int: l = [ e | e in s where not (e - 1 in s) ][i], int: r = [ e | e in s where not (e + 1 in s) ][i] } in l <= x /\ x <= r ); %%% for a fixed set predicate set_in_imp(var int: x, set of int: s__, var bool: b) = if is_fixed(b) then if fix(b) then x in s__ else true endif elseif has_bounds(x) /\ not (s__ subset dom(x)) then b -> x in s__ intersect dom(x) %% Use CSE else let { set of int: s = if has_bounds(x) then s__ intersect dom(x) else s__ endif, } in ( if dom(x) subset s then true elseif card(dom(x) intersect s)==0 then b==false elseif s == min(s)..max(s) then (b -> min(s) <= x) /\ (b -> x <= max(s)) else if card(dom(x))<=nMZN__UnaryLenMax_setInReif then %% PARAM TODO let { array[int] of var int: p = eq_encode(x); } in sum(i in s intersect dom(x))(p[i]) >= bool2int(b) else bool2int(b) <= fVarInBigSetOfInt(x, s) endif endif ) endif; function var 0..1: fVarInBigSetOfInt(var int: x, set of int: s) = let { array[int] of int: sL = [ e | e in s where not (e - 1 in s) ]; array[int] of int: sR = [ e | e in s where not (e + 1 in s) ]; constraint assert(length(sR)==length(sL), "N of lb and ub of sub-intervals of a set should be equal"); } in sum(i in index_set(sL)) (bool2int(x>=sL[i] /\ x<=sR[i])); %% use indicators %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% OTHER SET STUFF COMING FROM nosets.mzn %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% annotation bool_search(array[$X] of var bool: x, ann:a1, ann:a2, ann:a3) = let { array[int] of var bool: xx = array1d(x) } in int_search([bool2int(xx[i]) | i in index_set(xx)],a1,a2,a3); annotation warm_start( array[int] of var bool: x, array[int] of bool: v ) = warm_start( [ bool2int(x[i]) | i in index_set(x) ], [ bool2int(v[i]) | i in index_set(v) ] ); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% DOMAIN POSTPROCESSING BUILT-INS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Single variable: x = d <-> x_eq_d[d] predicate equality_encoding__POST(var int: x, array[int] of var int: x_eq_d); %%%%%%% var int: b: bool2int is a reverse_map, not passed to .fzn predicate set_in__POST(var int: x, set of int: s__); predicate set_in_reif__POST(var int: x, set of int: s__, var int: b); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% LOGICAL CONSTRAINTS TO THE SOLVER %%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%% var int: b: bool2int is a reverse_map, not passed to .fzn => REPEAT TESTS. TODO predicate int_lin_eq_reif__IND(array[int] of int: c, array[int] of var int: x, int: d, var int: b); predicate int_lin_le_reif__IND(array[int] of int: c, array[int] of var int: x, int: d, var int: b); predicate int_lin_ne__IND(array[int] of int: c, array[int] of var int: x, int: d); predicate aux_int_le_zero_if_0__IND(var int: x, var int: b); predicate float_lin_le_reif__IND(array[int] of float: c, array[int] of var float: x, float: d, var int: b); predicate aux_float_eq_if_1__IND(var float: x, var float: y, var int: b); predicate aux_float_le_zero_if_0__IND(var float: x, var int: b); predicate array_int_minimum__IND(var int: m, array[int] of var int: x); predicate array_int_maximum__IND(var int: m, array[int] of var int: x); predicate array_float_minimum__IND(var float: m, array[int] of var float: x); predicate array_float_maximum__IND(var float: m, array[int] of var float: x); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% XBZ cut generator, currently CPLEX only %%%%%%%%%%%%%%%%%%%%%%%%%% predicate array_var_float_element__XBZ_lb__cutgen(array[int] of var float: x, array[int] of var int: b, var float: z); libminizinc-2.4.2/share/minizinc/linear_scip/redefs_bool_imp.mzn000066400000000000000000000044251360574160400251310ustar00rootroot00000000000000include "redefs_lin_halfreifs.mzn"; % SIMPLE BOOLEAN LOGIC % TODO: why not check "is_fixed(r)" everywhere?? predicate bool_eq_imp(var bool: p, var bool: q, var bool: r) = if is_fixed(r) then if fix(r) then p = q else true endif else let { var int: x = bool2int(p), var int: y = bool2int(q), var int: z = bool2int(r) } in x + z <= y + 1 /\ y + z <= x + 1 endif; predicate bool_ne_imp(var bool: p, var bool: q, var bool: r) = bool_xor_imp(p, q, r); predicate bool_le_imp(var bool: p, var bool: q, var bool: r) = let { var int: x = bool2int(p), var int: y = bool2int(q), var int: z = bool2int(r), } in 1 - x + y >= z; predicate bool_lt_imp(var bool: p, var bool: q, var bool: r) = bool_and_imp(not p, q, r); predicate bool_or_imp(var bool: p, var bool: q, var bool: r) = array_bool_or_imp([p,q], r); predicate bool_and_imp(var bool: p, var bool: q, var bool: r) = array_bool_and_imp([p,q],r); predicate bool_xor_imp(var bool: p, var bool: q, var bool: r) = let { var int: x = bool2int(p), var int: y = bool2int(q), var int: z = bool2int(r), } in x + y >= z /\ x + y + z <= 2; % BOOLEAN ARRAY OPERATIONS predicate array_bool_or_imp(array[int] of var bool: a, var bool: b) = if forall( i in index_set( a ) )( is_fixed(a[i]) /\ not fix(a[i]) ) then not b elseif exists( i in index_set( a ) )( is_fixed(a[i]) /\ fix(a[i]) ) then true else let { array[index_set(a)] of var bool: a1; var int: x = bool2int(b), } in forall(i in index_set(a)) (a1[i] -> a[i]) /\ sum(a1) = x endif; predicate array_bool_and_imp(array[int] of var bool: a, var bool: b) = if is_fixed(b) then if fix(b) then forall(i in index_set(a))( a[i] ) else true endif elseif forall( i in index_set( a ) )( is_fixed(a[i]) /\ fix(a[i]) ) then true else let { var int: x = bool2int(b), array[index_set(a)] of var int: c = array1d(index_set(a), [ bool2int(a[i] ) | i in index_set(a) ]) } in forall(i in index_set(c)) ( c[i] >= x ) endif; %% No var int d, sorry TODO: why not??? predicate bool_lin_eq_imp(array[int] of int: c, array[int] of var bool: x, int: d, var bool: b) = aux_int_eq_if_1(sum(i in index_set(x))( c[i]*bool2int(x[i]) ), d, bool2int(b)); libminizinc-2.4.2/share/minizinc/linear_scip/redefs_bool_reifs.mzn000066400000000000000000000130441360574160400254510ustar00rootroot00000000000000/* % FlatZinc built-in redefinitions for linear solvers. % % AUTHORS % Sebastian Brand % Gleb Belov */ %-----------------------------------------------------------------------------% % % Logic operations % Use indicators for reifs (CPLEX)? Seems weak. % %-----------------------------------------------------------------------------% predicate bool_not(var bool: p, var bool: q) = bool2int(p) + bool2int(q) = 1; predicate bool_and(var bool: p, var bool: q, var bool: r) = % my_trace(" bool_and: \(p) /\\ \(q) <-> \(r) \n") /\ if false then int_lin_le_reif__IND( [-1, -1], [p, q], -2, r) else array_bool_and( [p, q], r ) % bool_and__INT(bool2int(p), bool2int(q), bool2int(r)) endif; predicate bool_and__INT(var int: x, var int: y, var int: z) = x + y <= z + 1 /\ %% x + y >= z * 2; % weak x >= z /\ y >= z; % strong predicate bool_or(var bool: p, var bool: q, var bool: r) = if false then int_lin_le_reif__IND( [-1, -1], [p, q], -1, r) elseif true then array_bool_or( [p, q], r ) else let { var int: x = bool2int(p), var int: y = bool2int(q), var int: z = bool2int(r) } in x + y >= z /\ % x + y <= z * 2; % weak x <= z /\ y <= z % strong endif; predicate bool_xor(var bool: p, var bool: q) = 1==p+q; predicate bool_xor(var bool: p, var bool: q, var bool: r) = if false then % int_lin_eq_reif__IND( [1, 1], [p, q], 1, r) /\ true else let { var int: x = bool2int(p), var int: y = bool2int(q), var int: z = bool2int(r) } in x <= y + z /\ y <= x + z /\ z <= x + y /\ x + y + z <= 2 endif; predicate bool_eq_reif(var bool: p, var bool: q, var bool: r) = %% trace(" bool_eq_reif: \(p), \(q), \(r) \n") /\ if is_fixed(r) then % frequent case if fix(r) = true then p = q else bool_not(p,q) endif elseif is_fixed(q) then if fix(q) = true then p = r else bool_not(p,r) endif elseif is_fixed(p) then if fix(p) = true then q = r else bool_not(q,r) endif elseif false then % int_lin_eq_reif__IND( [1, -1], [p, q], 0, r) /\ true else let { var int: x = bool2int(p), var int: y = bool2int(q), var int: z = bool2int(r) } in x + y <= z + 1 /\ x + z <= y + 1 /\ y + z <= x + 1 /\ x + y + z >= 1 endif; predicate bool_ne_reif(var bool: p, var bool: q, var bool: r) = bool_xor(p, q, r); predicate bool_le(var bool: p, var bool: q) = let { var int: x = bool2int(p), var int: y = bool2int(q) } in x <= y; predicate bool_le_reif(var bool: p, var bool: q, var bool: r) = if false then % int_lin_le_reif__IND( [1, -1], [p, q], 0, r) /\ true else let { var int: x = bool2int(p), var int: y = bool2int(q), var int: z = bool2int(r) } in 1 - x + y >= z /\ %% /\ 1 - x + y <= z * 2 not needed 1 - x <= z /\ y <= z % strong endif; predicate bool_lt(var bool: p, var bool: q) = not p /\ q; predicate bool_lt_reif(var bool: p, var bool: q, var bool: r) = (not p /\ q) <-> r; %-----------------------------------------------------------------------------% %% Reified disjunction predicate array_bool_or(array[int] of var bool: a, var bool: b) = if exists( i in index_set( a ) )( is_fixed(a[i]) /\ fix(a[i]) ) then b elseif is_fixed(b) then % frequent case if fix(b) = true then sum(i in index_set(a))( bool2int(a[i]) ) >= 1 %% >=1 seems better for MIPDomains... 5.4.19 else forall(i in index_set(a))( not a[i] ) endif else let { var int: x = bool2int(b), array[1..length(a)] of var int: c = [ bool2int(a[i]) | i in index_set(a) ] } in sum(c) >= x /\ % sum(c) <= x * length(a) % weak forall (i in index_set(a)) (x >= c[i]) % strong endif; %% Reified conjunction predicate array_bool_and(array[int] of var bool: a, var bool: b) = if exists( i in index_set( a ) )( is_fixed(a[i]) /\ not fix(a[i]) ) then not b elseif is_fixed(b) then % frequent case if fix(b) = false then sum(i in index_set(a))( bool2int(a[i]) ) <= length(a)-1 else forall(i in index_set(a))( a[i] ) endif else let { var int: x = bool2int(b), array[1..length(a)] of var int: c = [ bool2int(a[i]) | i in index_set(a) ] } in length(a) - sum(c) >= 1 - x /\ % length(a) - sum(c) <= (1 - x) * length(a); % weak forall (i in index_set(a)) (x <= c[i]) % strong endif; % predicate array_bool_xor(array[int] of var bool: a) = .. sum(a) is odd .. predicate array_bool_xor(array[int] of var bool: a) = let { var 0..(length(a)-1) div 2: m, var 1..((length(a)-1) div 2)*2+1: ss = sum(i in index_set(a))( bool2int(a[i]) ) } in ss == 1 + 2 * m; predicate bool_clause(array[int] of var bool: p, array[int] of var bool: n) = sum(i in index_set(p))( bool2int(p[i]) ) - sum(i in index_set(n))( bool2int(n[i]) ) + length(n) >= 1; predicate bool_lin_eq(array[int] of int: c, array[int] of var bool: x, var int: d) :: promise_total = sum(i in index_set(x))( c[i]*bool2int(x[i]) ) == d; predicate bool_lin_eq_reif(array[int] of int: c, array[int] of var bool: x, int: d, var bool: b) = %% No var int d, sorry aux_int_eq_iff_1(sum(i in index_set(x))( c[i]*bool2int(x[i]) ), d, bool2int(b)); libminizinc-2.4.2/share/minizinc/linear_scip/redefs_lin_halfreifs.mzn000066400000000000000000000207421360574160400261360ustar00rootroot00000000000000/* % FlatZinc built-in redefinitions for linear solvers. % % AUTHORS % Sebastian Brand % Gleb Belov */ %-----------------------------------------------------------------------------% % Auxiliary: indicator constraints % p -> x # 0 where p is a 0/1 variable and # is a comparison % Base cases %% used e.g. in element predicate aux_float_eq_if_1(var float: x, var float: y, var int: p) = if is_fixed(p) then if 1==fix(p) then x==y else true endif elseif is_fixed(x) /\ is_fixed(y) then %%% Needed to avoid constant domain var if fix(x)!=fix(y) then p==0 else true endif elseif is_fixed(x-y) then %%% Hypothetically possible to land here if 0.0!=fix(x-y) then p==0 else true endif elseif fPostprocessDomains /\ fPostproDom_AUX /\ fPostproDom_DIFF then aux_float_eq_zero_if_1__POST(x - y, p, p) elseif fMZN__UseIndicators then aux_float_eq_if_1__IND(x, y, p) else aux_float_le_if_1(x, y, p) /\ aux_float_ge_if_1(x, y, p) endif; predicate aux_int_eq_if_1(var int: x, var int: y, var int: p) = if is_fixed(p) then if fix(p) = 1 then (x = y) else true endif elseif is_fixed(x) /\ is_fixed(y) then if fix(x) != fix(y) then (p = 0) else true endif % elseif is_fixed(x-y) then % TODO: Necessary for integers?? % if 0.0!=fix(x-y) then p==0 else true endif % elseif fPostprocessDomains /\ fPostproDom_AUX /\ fPostproDom_DIFF then % % TODO MIPDomains % elseif fMZN__UseIndicators then % TODO: Necessary for integers?? % aux_float_eq_if_1__IND(x, y, p) else aux_int_le_if_1(x, y, p) /\ aux_int_ge_if_1(x, y, p) endif; predicate aux_float_ne_if_1(var float: x, var float: y, var int: p) = if is_fixed(p) then if fix(p) = 1 then (x != y) else true endif elseif is_fixed(x) /\ is_fixed(y) then %%% Needed to avoid constant domain var if (fix(x) = fix(y)) then (p = 0) else true endif elseif is_fixed(x-y) then %%% Hypothetically possible to land here if (0.0 = fix(x-y)) then (p = 0) else true endif % TODO: What is necessary for not equals? % elseif fPostprocessDomains /\ fPostproDom_AUX /\ fPostproDom_DIFF then % aux_float_ne_zero_if_1__POST(x - y, p, p) % elseif fMZN__UseIndicators then % aux_float_ne_if_1__IND(x, y, p) else let { array[1..2] of var bool: q } in ( q[1] -> (x < y) ) /\ ( q[2] -> (x > y) ) /\ (sum(q) = p) endif; predicate aux_int_ne_if_1(var int: x, var int: y, var int: p) = if is_fixed(p) then if fix(p) = 1 then (x != y) else true endif elseif is_fixed(x) /\ is_fixed(y) then if fix(x) = fix(y) then (p = 0) else true endif % elseif is_fixed(x-y) then % TODO: Necessary for integers?? % if 0.0!=fix(x-y) then p==0 else true endif % elseif fPostprocessDomains /\ fPostproDom_AUX /\ fPostproDom_DIFF then % % TODO MIPDomains % elseif fMZN__UseIndicators then % TODO: Necessary for integers?? % aux_float_eq_if_1__IND(x, y, p) else let { array[1..2] of var bool: q } in ( q[1] -> (x < y) ) /\ ( q[2] -> (x > y) ) /\ (sum(q) = p) endif; predicate aux_int_le_zero_if_0(var int: x, var int: p) = if is_fixed(p) then if 0==fix(p) then x<=0 else true endif %% 0==fix !! elseif lb(x)>0 then p==1 elseif not (0 in dom(x)) then let { constraint assert( ub(x) < infinity, "aux_int_le_zero_if_0: variable \(x)'s domain: dom(\(x)) = \(dom(x)), should have finite upper bound\n" ), set of int: sDomNeg = dom(x) intersect -infinity..-1, constraint assert( card( sDomNeg ) > 0, "Variable \(x): dom(\(x)) = \(dom(x)), but dom() intersect -inf..-1: \(sDomNeg)\n" ), } in aux_int_le_if_0( x, max( sDomNeg ), p ) elseif fPostprocessDomains /\ fPostproDom_AUX then aux_int_le_zero_if_1__POST(x, 1-p) elseif fMZN__UseIndicators then aux_int_le_zero_if_0__IND(x, p) else assert( ub(x)0.0 then p==1 elseif fPostprocessDomains /\ fPostproDom_AUX then aux_float_le_zero_if_1__POST(x, 1-p, 1-p) elseif fMZN__UseIndicators then aux_float_le_zero_if_0__IND(x, p) else x <= ub(x) * p endif; predicate aux_float_lt_zero_if_0(var float: x, var int: p) = assert( has_bounds(x), "Variable \(x) needs finite bounds for a big-M constraint" ) /\ if is_fixed(p) then if 0==fix(p) then x<0.0 else true endif elseif lb(x)>=0.0 then p==1 elseif fPostprocessDomains /\ fPostproDom_AUX then aux_float_lt_zero_if_1__POST(x, 1-p, 1-p, float_lt_EPS) elseif fMZN__UseIndicators then aux_float_le_zero_if_0__IND(x+float_lt_EPS, p) %% Here just absolute EPS, TODO else %% let { float: rho = float_lt_EPS_coef__ * max(abs(ub(x)), abs(lb(x))) } % same order of magnitude as ub(x) let { float: rho = float_lt_EPS } % absolute eps in %%% This one causes 2x- derivation of EPS: %% x < (ub(x) + rho) * p %%% Better? x <= (ub(x) + rho) * p - rho %%% This just uses absolute eps: %% x < (ub(x) + float_lt_EPS) * p endif; % Derived cases predicate aux_int_le_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y, p); predicate aux_int_ge_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x, p); predicate aux_int_le_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y, 1 - p); predicate aux_int_ge_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x, 1 - p); predicate aux_int_lt_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y + 1, p); predicate aux_int_gt_if_0(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x + 1, p); predicate aux_int_lt_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(x - y + 1, 1 - p); predicate aux_int_gt_if_1(var int: x, var int: y, var int: p) = aux_int_le_zero_if_0(y - x + 1, 1 - p); %% int: switching differences to float to avoid creating integer vars /* Used anywhere? predicate aux_int_le_if_0(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(x - y, p); predicate aux_int_ge_if_0(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(y - x, p); predicate aux_int_le_if_1(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(x - y, 1 - p); predicate aux_int_ge_if_1(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(y - x, 1 - p); predicate aux_int_lt_if_0(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(x - y + 1.0, p); predicate aux_int_gt_if_0(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(y - x + 1.0, p); predicate aux_int_lt_if_1(var float: x, float: y, var int: p) = aux_float_le_zero_if_0(x - y + 1.0, 1 - p); */ predicate aux_float_le_if_0(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(x - y, p); predicate aux_float_ge_if_0(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(y - x, p); predicate aux_float_le_if_1(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(x - y, 1 - p); predicate aux_float_ge_if_1(var float: x, var float: y, var int: p) = aux_float_le_zero_if_0(y - x, 1 - p); predicate aux_float_lt_if_0(var float: x, var float: y, var int: p) = aux_float_lt_zero_if_0(x - y, p); predicate aux_float_gt_if_0(var float: x, var float: y, var int: p) = aux_float_lt_zero_if_0(y - x, p); predicate aux_float_lt_if_1(var float: x, var float: y, var int: p) = aux_float_lt_zero_if_0(x - y, 1 - p); predicate aux_float_gt_if_1(var float: x, var float: y, var int: p) = aux_float_lt_zero_if_0(y - x, 1 - p); % -------------------------- Domains postpro --------------------------- %% To avoid looking if an original int var x-y exists and has eq_encode: %% Passing both int and float version of the indicator for flexibility: predicate aux_float_eq_zero_if_1__POST(var float: x, var int: pI, var float: p); predicate aux_int_le_zero_if_1__POST(var int: x, var int: p); predicate aux_float_le_zero_if_1__POST(var float: x, var int: pI, var float: p); predicate aux_float_lt_zero_if_1__POST(var float: x, var int: pI, var float: p, float: eps); libminizinc-2.4.2/share/minizinc/linear_scip/redefs_lin_imp.mzn000066400000000000000000000172451360574160400247640ustar00rootroot00000000000000include "redefs_lin_halfreifs.mzn"; include "redefs_lin_reifs.mzn"; %% var, var predicate int_le_imp(var int: x, var int: y, var bool: b) = if is_fixed(b) then if fix(b) then x<=y else true endif elseif ub(x)<=lb(y) then true elseif lb(x)>ub(y) then (not b) % elseif fPostprocessDomains /\ fPostproDom_DIFF then % % TODO MIPDomains else aux_int_le_if_1(x, y, b) endif; %% var, var predicate int_lt_imp(var int: x, var int: y, var bool: b) = if is_fixed(x) then int_le_imp(x + 1, y, b) else int_le_imp(x, y - 1, b) endif; %% var, var predicate int_eq_imp(var int: x, var int: y, var bool: b) = if is_fixed(b) then if fix(b) then (x = y) else true endif elseif card( dom(x) intersect dom(y) ) > 0 then if is_fixed(x) then if is_fixed(y) then b -> (fix(x) = fix(y)) else int_eq_imp(y, fix(x), b) endif elseif is_fixed(y) then int_eq_imp(x, fix(y), b) % elseif fPostprocessDomains /\ fPostproDom_DIFF then % % TODO MIPDomains else aux_int_eq_if_1(x, y, b) endif else not b endif; %% var, const predicate int_eq_imp(var int: x, int: y, var bool: b) = if is_fixed(b) then if fix(b) then (x = y) else true endif elseif y in dom(x) then if is_fixed(x) then b -> (y = fix(x)) % elseif fPostprocessDomains then % % TODO MIPDomains else aux_int_eq_if_1(x, y, b) endif else not b endif; %% var, var predicate int_ne_imp(var int: x, var int: y, var bool: b) = if is_fixed(b) then if fix(b) then (x != y) else true endif elseif (ub(x) < lb(y)) \/ (lb(x) > ub(y)) then true else if is_fixed(x) then if is_fixed(y) then b -> (fix(x) != fix(y)) else int_ne_imp(y, fix(x), b) endif elseif is_fixed(y) then int_ne_imp(x, fix(y), b) % elseif fPostprocessDomains /\ fPostproDom_DIFF then % % TODO MIPDomains else aux_int_ne_if_1(x, y, b) endif endif; %% var, const predicate int_ne_imp(var int: x, int: y, var bool: b) = if is_fixed(b) then if fix(b) then (x != y) else true endif elseif (ub(x) < lb(y)) \/ (lb(x) > ub(y)) then true else if is_fixed(x) then b -> (y != fix(x)) % elseif fPostprocessDomains then % % TODO MIPDomains else aux_int_ne_if_1(x, y, b) endif endif; %-----------------------------------------------------------------------------% %% lin_expr, const predicate int_lin_le_imp(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = if (d = 0) /\ (length(c) = 2) /\ (abs(c[1]) = 1) /\ (c[1] = -1 * c[2]) then if (c[1] < 0) then int_le_imp(x[2], x[1], b) else int_le_imp(x[1], x[2], b) endif elseif fPostprocessDomains /\ fPostproDom_DIFF then int_le_imp(sum(i in index_set(x))(c[i] * x[i]), d, b) elseif fAvoidNI then aux_float_le_if_1(sum2float(c, x), d, b) else aux_int_le_if_1(sum(i in index_set(x))(c[i] * x[i]), d, b) endif; predicate int_lin_lt_imp(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = if true then abort("int_lin_lt_imp not supposed to be called") else int_lin_le_imp(c, x, d - 1, b) endif; %% lin_expr, const predicate int_lin_eq_imp(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = if (d = 0) /\ (length(c) = 2) /\ (abs(c[1]) = 1) /\ (c[1] = -1 * c[2]) then int_ne_imp(x[1], x[2], b) elseif fPostprocessDomains /\ fPostproDom_DIFF then int_eq_imp(sum(i in index_set(x))(c[i] * x[i]), d, b) elseif fAvoidNI then aux_float_eq_if_1(sum2float(c, x), d, b) else aux_int_eq_if_1(sum(i in index_set(x))(c[i] * x[i]), d, b) endif; %% lin_expr, const predicate int_lin_ne_imp(array[int] of int: c, array[int] of var int: x, int: d, var bool: b) = if (d = 0) /\ (length(c) = 2) /\ (abs(c[1]) = 1) /\ (c[1] = -1 * c[2]) then int_ne_imp(x[1], x[2], b) elseif fPostprocessDomains /\ fPostproDom_DIFF then int_ne_imp(sum(i in index_set(x))(c[i] * x[i]), d, b) elseif fAvoidNI then aux_float_ne_if_1(sum2float(c, x), d, b) else aux_int_ne_if_1(sum(i in index_set(x))(c[i] * x[i]), d, b) endif; %-----------------------------------------------------------------------------% %% var float, var float predicate float_le_imp(var float: x, var float: y, var bool: b) = if is_fixed(b) then if fix(b) then x <= y else true endif elseif ub(x) <= lb(y) then true elseif lb(x) > ub(y) then (not b) % elseif fPostprocessDomains /\ fPostproDom_DIFF then % % TODO MIPDomains else aux_float_le_if_1(x, y, b) endif; %% var float, var float predicate float_lt_imp(var float: x, var float: y, var bool: b) = if is_fixed(b) then if fix(b) then (x < y) else true endif % elseif fPostprocessDomains /\ fPostproDom_DIFF then % % TODO MIPDomains else aux_float_lt_if_1(x, y, b) endif; %% var float, var float predicate float_eq_imp(var float: x, var float: y, var bool: b) = if is_fixed(b) then if fix(b) then (x = y) else true endif elseif (ub(x) < lb(y)) \/ (lb(x) > ub(y)) then not b elseif is_fixed(x) /\ is_fixed(y) then b -> (fix(x) == fix(y)) % elseif fPostprocessDomains /\ fPostproDom_DIFF then % % TODO MIPDomains else aux_float_eq_if_1(x, y, b) endif; %% var float, var float predicate float_ne_imp(var float: x, var float: y, var bool: b) = if is_fixed(b) then if fix(b) then (x != y) else true endif elseif (ub(x) < lb(y)) \/ (lb(x) > ub(y)) then true elseif is_fixed(x) /\ is_fixed(y) then b -> (fix(x) != fix(y)) % elseif fPostprocessDomains /\ fPostproDom_DIFF then % % TODO MIPDomains else aux_float_ne_if_1(x, y, b) endif; %-----------------------------------------------------------------------------% predicate float_lin_eq_imp(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = if (d = 0.0) /\ (length(c) = 2) /\ (abs(c[1]) = 1.0) /\ (c[1] = -1.0 * c[2]) then float_eq_imp(x[1], x[2], b) elseif fPostprocessDomains /\ fPostproDom_DIFF then float_eq_imp(sum(i in index_set(x))(c[i] * x[i]), d, b) else aux_float_eq_if_1(sum(i in index_set(x))(c[i] * x[i]), d, b) endif; predicate float_lin_ne_imp(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = if (d = 0.0) /\ (length(c) = 2) /\ (abs(c[1]) = 1.0) /\ (c[1] = -1.0 * c[2]) then float_ne_imp(x[1], x[2], b) elseif fPostprocessDomains /\ fPostproDom_DIFF then float_ne_imp(sum(i in index_set(x))(c[i] * x[i]), d, not b) else aux_float_ne_if_1(sum(i in index_set(x))(c[i] * x[i]), d, b) endif; predicate float_lin_le_imp(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = if (d = 0.0) /\ (length(c) = 2) /\ (abs(c[1]) = 1.0) /\ (c[1] = -1.0 * c[2]) then if (c[1] < 0.0) then float_le_imp(x[2], x[1], b) else float_le_imp(x[1], x[2], b) endif elseif fPostprocessDomains /\ fPostproDom_DIFF then float_le_imp(sum(i in index_set(x))(c[i] * x[i]), d, b) else aux_float_le_if_1(sum(i in index_set(x))(c[i] * x[i]), d, b) endif; predicate float_lin_lt_imp(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = if (d = 0.0) /\ (length(c) = 2) /\ (abs(c[1]) = 1.0) /\ (c[1] = -1.0 * c[2]) then if (c[1] < 0.0) then float_lt_imp(x[2], x[1], b) else float_lt_imp(x[1], x[2], b) endif elseif fPostprocessDomains /\ fPostproDom_DIFF then float_lt_imp(sum(i in index_set(x))(c[i] * x[i]), d, b) else aux_float_lt_if_1(sum(i in index_set(x))(c[i] * x[i]), d, b) endif; libminizinc-2.4.2/share/minizinc/linear_scip/redefs_lin_reifs.mzn000066400000000000000000000364471360574160400253140ustar00rootroot00000000000000/* % FlatZinc built-in redefinitions for linear solvers. % % AUTHORS % Sebastian Brand % Gleb Belov */ %-----------------------------------------------------------------------------% % % Linear equations and inequations % TODO Use indicators for (half)reifs. % Otherwise and more using unary encoding for reasonable domains % %-----------------------------------------------------------------------------% % Domains: reduce all to aux_ stuff? %% never use Concert's reif feature %% var, var predicate int_le_reif(var int: x, var int: y, var bool: b) = %% trace(" int_le_reif VV: \(x), \(y), \(b) \n") /\ if is_fixed(b) then if true==fix(b) then x<=y else x>y endif elseif ub(x)<=lb(y) then b==true elseif lb(x)>ub(y) then b==false elseif fPostprocessDomains /\ fPostproDom_DIFF then int_le_reif__POST(x-y, 0, b) else int_le_reif__NOPOST(x, y, b) endif ; %% const, var predicate int_le_reif(int: x, var int: y, var bool: b) = %% trace(" int_le_reif CV: \(x), \(y), \(b) \n") /\ if is_fixed(b) then if true==fix(b) then x<=y else x>y endif elseif ub(x)<=lb(y) then b==true elseif lb(x)>ub(y) then b==false elseif not (x in dom(y)) then %% dom(y) has holes let { set of int: sDom2 = dom(y) intersect x+1..infinity, constraint assert( card( sDom2 ) > 0, "Variable: dom(\(y)) = \(dom(y)), but dom() intersect \(x)..inf: \(sDom2)\n" ), } in b <-> min( sDom2 ) <= y elseif fPostprocessDomains then int_ge_reif__POST(y, x, b) else int_le_reif(-y, -x, b) endif ; %% var, const predicate int_le_reif(var int: x, int: y, var bool: b) = %% trace(" int_le_reif VC: \(x), \(y), \(b) \n") /\ if is_fixed(b) then if true==fix(b) then x<=y else x>y endif elseif ub(x)<=lb(y) then b==true elseif lb(x)>ub(y) then b==false elseif not (y in dom(x)) then %% dom(x) has holes let { set of int: sDom2 = dom(x) intersect -infinity..y-1, constraint assert( card( sDom2 ) > 0, "Variable: dom(\(x)) = \(dom(x)), but dom() intersect -inf..\(y): \(sDom2)\n" ), } in b <-> x <= max( sDom2 ) else if fPostprocessDomains then int_le_reif__POST(x, y, b) else int_le_reif__NOPOST(x, y, b) endif endif ; %% var int, var int predicate int_le_reif__NOPOST(var int: x, var int: y, var bool: b) = aux_int_le_if_1(x, y, b) /\ %% This can call POSTs... TODO aux_int_gt_if_0(x, y, b) ; %% var, var predicate int_lt_reif(var int: x, var int: y, var bool: b) = %% int_le_reif(x-y, -1, b); %% This would produce a new variable x-y and possibly POST it %% but it looks like differences should not be if is_fixed( x ) then int_le_reif(x+1, y, b) else int_le_reif(x, y-1, b) endif; %% var, var predicate int_ne(var int: x, var int: y) = if fPostproDom_DIFF then int_ne(x-y, 0) else int_ne__SIMPLE(x-y, 0) endif; %% var, const predicate int_ne(var int: x, int: y) = if y in dom(x) then if y==ub(x) then x <= y-1 elseif y==lb(x) then x >= y+1 elseif fPostprocessDomains then int_ne__POST(x, y) elseif card(dom(x))y) endif; %% var, var predicate int_eq_reif(var int: x, var int: y, var bool: b) = %% trace(" int_eq_reif VV: \(x), \(y), \(b) \n") /\ if is_fixed(b) then if fix(b) then x==y else x!=y endif elseif card(dom(x) intersect dom(y))>0 then if is_fixed(x) then if is_fixed(y) then b <-> fix(x)==fix(y) else int_eq_reif(y, fix(x), b) endif elseif is_fixed(y) then int_eq_reif(x, fix(y), b) elseif fPostprocessDomains /\ fPostproDom_DIFF then int_eq_reif(x-y, 0, b) else aux_int_eq_iff_1(x, y, b) endif else not b endif; %% var, const predicate int_eq_reif(var int: x, int: y, var bool: b) = %% trace(" int_eq_reif VC: \(x), \(y), \(b) \n") /\ if is_fixed(b) then if fix(b) then x==y else x!=y endif elseif y in dom(x) then if is_fixed(x) then b <-> y==fix(x) elseif card(dom(x))==2 then x == max(dom(x) diff {y}) + b*(y - max(dom(x) diff {y})) %% This should directly connect b to var 0..1: x elseif fPostprocessDomains then int_eq_reif__POST(x, y, b) %%% THIS seems pretty complex, especially for binaries, and does not connect to eq_encoding (/ MIPD?) %% elseif y==lb(x) then %% int_lt_reif(y, x, not b) %% elseif y==ub(x) then %% int_lt_reif(x, y, not b) elseif card(dom(x))y endif elseif false then float_lin_le_reif__IND( [1.0, -1.0], [x, y], 0.0, b) elseif ub(x) <= y then b == true elseif lb(x) > y then b == false elseif fPostprocessDomains then float_le_reif__POST(x, y, b, float_lt_EPS) else float_le_reif__NOPOST(x, y, b) endif; %% const, var float predicate float_le_reif(float: x, var float: y, var bool: b) = if is_fixed(b) then if true==fix(b) then x<=y else x>y endif elseif false then float_lin_le_reif__IND( [1.0, -1.0], [x, y], 0.0, b) elseif ub(x) <= lb(y) then b == true elseif lb(x) > ub(y) then b == false elseif fPostprocessDomains then float_ge_reif__POST(y, x, b, float_lt_EPS) else float_le_reif(-y, -x, b) endif; %% var float, var float predicate float_le_reif(var float: x, var float: y, var bool: b) = if is_fixed(b) then if true==fix(b) then x<=y else x>y endif elseif ub(x)<=lb(y) then b==true elseif lb(x)>ub(y) then b==false elseif fPostprocessDomains /\ fPostproDom_DIFF then float_le_reif(x-y, 0.0, b) else float_le_reif__NOPOST(x-y, 0, b) endif ; %% var float, var float predicate float_le_reif__NOPOST(var float: x, var float: y, var bool: b) = aux_float_le_if_1(x, y, (b)) /\ %% Can call __POSTs TODO aux_float_gt_if_0(x, y, (b)) ; %% TODO predicate float_lt_reif(var float: x, var float: y, var bool: b) = %% Actually = float_le_reif(x, y-eps, b). if is_fixed(b) then if true==fix(b) then x=y endif elseif fPostprocessDomains /\ fPostproDom_DIFF then aux_float_lt_zero_iff_1__POST(x - y, b, float_lt_EPS) else aux_float_lt_if_1(x, y, (b)) /\ aux_float_ge_if_0(x, y, (b)) endif; %% var, const predicate float_ne(var float: x, float: y) = if fPostprocessDomains then float_ne__POST(x, y, float_lt_EPS) else float_ne__SIMPLE(x, y) endif; predicate float_ne__SIMPLE(var float: x, var float: y) = if true then let { var 0..1: p } in aux_float_lt_if_1(x, y, (p)) /\ aux_float_gt_if_0(x, y, (p)) else %TODO: Why is this not half-reified? 1 == (x>y) + (xub(y) then b == false elseif is_fixed(x) /\ is_fixed(y) then b == (fix(x) == fix(y)) elseif fPostprocessDomains /\ fPostproDom_DIFF then float_eq_reif__POST(x-y, 0, b, float_lt_EPS) else aux_float_eq_iff_1(x, y, (bool2int(b))) endif; predicate float_ne_reif(var float: x, var float: y, var bool: b) = float_eq_reif(x, y, not (b)); %-----------------------------------------------------------------------------% predicate float_lin_eq_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = if fPostprocessDomains /\ fPostproDom_DIFF then float_eq_reif(sum(i in index_set(x))( c[i]*x[i] ), d, b) else aux_float_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, b) endif; predicate float_lin_ne_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = if fPostprocessDomains /\ fPostproDom_DIFF then float_ne_reif(sum(i in index_set(x))( c[i]*x[i] ), d, not b) else aux_float_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, not b) endif; predicate float_lin_le_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = if fPostprocessDomains /\ fPostproDom_DIFF then float_le_reif(sum(i in index_set(x))( c[i]*x[i] ), d, b) else float_le_reif__NOPOST(sum(i in index_set(x))( c[i]*x[i] ), d, b) endif; predicate float_lin_lt_reif(array[int] of float: c, array[int] of var float: x, float: d, var bool: b) = float_lt_reif(sum(i in index_set(x))( c[i]*x[i] ), d, b); %-----------------------------------------------------------------------------% % Auxiliary: equality reified onto a 0/1 variable predicate aux_int_eq_iff_1(var int: x, var int: y, var int: p) = if is_fixed(p) then if 1==fix(p) then x==y else x!=y endif elseif fPostprocessDomains /\ fPostproDom_DIFF then abort(" aux_int_eq_iff_1 should not be used with full domain postprocessing") elseif false then true elseif fAuxIntEqOLD00 then let { array[1..2] of var 0..1: q } in aux_int_le_if_1(x, y, p) /\ aux_int_ge_if_1(x, y, p) /\ aux_int_lt_if_0(x, y, q[1]) /\ aux_int_gt_if_0(x, y, q[2]) /\ sum(q) == p + 1 else %% redundant p == (x<=y /\ y<=x) /\ 1+p == (x<=y) + (y<=x) endif; predicate aux_int_eq_iff_1__float(var float: x, float: y, var int: p) = if fAuxIntEqOLD00 then assert( false, "Don't use aux_int_eq_iff_1__float" ) /* let { array[1..2] of var 0..1: q } in aux_int_le_if_1(x, y, p) /\ aux_int_ge_if_1(x, y, p) /\ aux_int_lt_if_0(x, y, q[1]) /\ aux_int_gt_if_0(x, y, q[2]) /\ sum(q) == p + 1 */ else assert( false, "Don't use aux_int_eq_iff_1__float with fAuxIntEqOLD00" ) endif; % Alternative 2 predicate aux_int_eq_iff_1__WEAK1(var int: x, var int: y, var int: p) = let { array[1..2] of var 0..1: q_458 } in aux_int_lt_if_0(x - p, y, q_458[1]) /\ aux_int_gt_if_0(x + p, y, q_458[2]) /\ sum(q_458) <= 2 - 2*p /\ sum(q_458) <= 1 + p; % Alternative 1 predicate alt_1_aux_int_eq_iff_1(var int: x, var int: y, var int: p) = let { array[1..2] of var 0..1: q } in aux_int_lt_if_0(x - p, y, q[1]) /\ aux_int_gt_if_0(x + p, y, q[2]) /\ q[1] <= 1 - p /\ q[2] <= 1 - p /\ sum(q) <= 1 + p; predicate aux_float_eq_iff_1(var float: x, var float: y, var int: p) = if is_fixed(p) then if 1==fix(p) then x==y else x!=y endif elseif fPostprocessDomains /\ fPostproDom_DIFF then abort(" aux_float_eq_iff_1 should not be used with full domain postprocessing") elseif fAuxFloatEqOLD00 then let { array[1..2] of var 0..1: q } in aux_float_le_if_1(x, y, p) /\ aux_float_ge_if_1(x, y, p) /\ aux_float_lt_if_0(x, y, (q[1])) /\ aux_float_gt_if_0(x, y, (q[2])) /\ sum(i in 1..2)((q[i])) == 1 + p else %% redundant p == (x<=y /\ y<=x) /\ 1+p == (x<=y) + (y<=x) endif; % ----------------------------- Domains postpro --------------------------- %%%%%%%%%%%%%%%%%% predicate int_le_reif__POST(var int: x, var int: y, var int: b); %%%%%%%%%%%%%%%%%% predicate int_le_reif__POST(int: x, var int: y, var int: b); %%%%%%% var int: b: bool2int is a reverse_map, not passed to .fzn %% var, const predicate int_le_reif__POST(var int: x, int: y, var int: b); %% var, const predicate int_ge_reif__POST(var int: x, int: y, var int: b); %% var, const predicate int_eq_reif__POST(var int: x, int: y, var int: b); %% var, const predicate int_ne__POST(var int: x, int: y); %%%%%%%%%%%%%%%%%% predicate float_le_reif__POST(var float: x, var float: y, var int: b); %%%%%%%%%%%%%%%%%% predicate float_le_reif__POST(float: x, var float: y, var int: b); %% var, const predicate float_le_reif__POST(var float: x, float: y, var int: b, float: epsRel); %% var, const predicate float_ge_reif__POST(var float: x, float: y, var int: b, float: epsRel); %% var, var predicate aux_float_lt_zero_iff_1__POST(var float: x, var int: b, float: epsRel); %% var, const predicate float_eq_reif__POST(var float: x, float: y, var int: b, float: epsRel); %% var, const predicate float_ne__POST(var float: x, float: y, float: epsRel); libminizinc-2.4.2/share/minizinc/linear_scip/subcircuit_wDummy.mzn000066400000000000000000000057321360574160400255210ustar00rootroot00000000000000/* Linearized version * Uses a predicate which constructs a subcircuit which always includes an extra dummy vertex * Is worse than the just slightly adapted standard variant... */ include "alldifferent.mzn"; /** @group globals Constrains the elements of \a x to define a subcircuit where \a x[\p i] = \p j means that \p j is the successor of \p i and \a x[\p i] = \p i means that \p i is not in the circuit. */ %% Linear version predicate subcircuit(array[int] of var int: x) = let { set of int: S = index_set(x), int: l = min(S), int: u = max(S), int: n = card(S), constraint forall(i in S)(x[i] in l..u), array[l..u+1] of var l..u+1: xx, constraint forall(i in S)(xx[i] in dom(x[i]) union {u+1}), } in alldifferent(x) /\ subcircuit_wDummy(xx) /\ forall( i in S, j in dom(x[i]) )( %% also when i==j? eq_encode(x[i])[j] >= 2*eq_encode(xx[i])[j] + eq_encode(xx[i])[u+1] + eq_encode(xx[u+1])[j] - 1 %% -1 /\ eq_encode(x[i])[j] >= eq_encode(xx[i])[j] /\ eq_encode(x[i])[j] <= eq_encode(xx[i])[j] + eq_encode(xx[i])[u+1] /\ eq_encode(x[i])[j] <= eq_encode(xx[i])[j] + eq_encode(xx[u+1])[j] ) /\ forall( i in S )( eq_encode(x[i])[i] == eq_encode(xx[i])[i] ) ; %% Should include at least 2 nodes if >0? %% xx[n] is dummy predicate subcircuit_wDummy(array[int] of var int: x) = let { set of int: S = index_set(x), int: l = min(S), int: u = max(S), int: n = card(S), set of int: S__ = S diff {u}, %% the real nodes array[S__] of var 2..n: order, %% constraint order[n]==1, %% fix the dummy %% var bool: empty = (firstin == u+1), no, break 2-cycles with dummy } in alldifferent(x) /\ % NO alldifferent(order) /\ %%% MTZ model. Note that INTEGER order vars seem better!: forall( i in S__, j in dom(x[i]) where i!=j /\ j!=u )( order[i] - order[j] + (n-1)*eq_encode(x[i])[j] % + (n-3)*bool2int(x[j]==i) %% the Desrochers & Laporte '91 term % --- strangely enough it is much worse on vrp-s2-v2-c7_vrp-v2-c7_det_ADAPT_1_INVERSE.mzn! <= n-2 ) /\ %% Break 2-cycles with dummy: forall( i in S__ )( eq_encode(x[i])[u] + eq_encode(x[u])[i] <= 1 /\ %% Ensure dummy is in: if i in dom(x[i]) then eq_encode(x[i])[i] >= eq_encode(x[u])[u] else true endif ) /\ % Symmetry? Each node that is not in is numbered after the lastin node. forall(i in S) ( true % (not ins[i]) <-> (n == order[i]) ) ; predicate subcircuit_reif(array[int] of var int: x, var bool: b) = abort("Reified subcircuit/1 is not supported."); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/000077500000000000000000000000001360574160400175505ustar00rootroot00000000000000libminizinc-2.4.2/share/minizinc/std/all_different.mzn000066400000000000000000000013301360574160400230710ustar00rootroot00000000000000include "all_different_int.mzn"; include "all_different_set.mzn"; include "analyse_all_different.mzn"; /** @group globals.alldifferent Constrain the array of integers \a x to be all different. */ predicate all_different(array[$X] of var int: x) = analyse_all_different(array1d(x)) /\ all_different_int(array1d(x)); /** @group globals.alldifferent Constrain the array of sets of integers \a x to be all different. */ predicate all_different(array[$X] of var set of int: x) = all_different_set(array1d(x)); % Synonyms for the above. predicate alldifferent(array[$X] of var int: x) = all_different_int(array1d(x)); predicate alldifferent(array[$X] of var set of int: x) = all_different_set(array1d(x)); libminizinc-2.4.2/share/minizinc/std/all_different_int.mzn000066400000000000000000000007631360574160400237540ustar00rootroot00000000000000include "fzn_all_different_int.mzn"; include "fzn_all_different_int_reif.mzn"; %-----------------------------------------------------------------------------% % Constrains the array of objects 'x' to be all different. %-----------------------------------------------------------------------------% predicate all_different_int(array[int] of var int: x) = fzn_all_different_int(x); predicate all_different_int_reif(array[int] of var int: x, var bool: b) = fzn_all_different_int_reif(x, b); libminizinc-2.4.2/share/minizinc/std/all_different_set.mzn000066400000000000000000000007741360574160400237570ustar00rootroot00000000000000include "fzn_all_different_set.mzn"; include "fzn_all_different_set_reif.mzn"; %-----------------------------------------------------------------------------% % Constrains the array of objects 'x' to be all different. %-----------------------------------------------------------------------------% predicate all_different_set(array[int] of var set of int: x) = fzn_all_different_set(x); predicate all_different_set(array[int] of var set of int: x, var bool: b) = fzn_all_different_set_reif(x, b); libminizinc-2.4.2/share/minizinc/std/all_disjoint.mzn000066400000000000000000000006071360574160400227540ustar00rootroot00000000000000include "fzn_all_disjoint.mzn"; include "fzn_all_disjoint_reif.mzn"; /** @group globals.alldifferent Constrain the array of sets of integers \a S to be pairwise disjoint. */ predicate all_disjoint(array[$X] of var set of int: S) = fzn_all_disjoint(array1d(S)); predicate all_disjoint_reif(array[$X] of var set of int: S, var bool: b) = fzn_all_disjoint_reif(array1d(S), b); libminizinc-2.4.2/share/minizinc/std/all_equal.mzn000066400000000000000000000006271360574160400222420ustar00rootroot00000000000000include "all_equal_int.mzn"; include "all_equal_set.mzn"; /** @group globals.alldifferent Constrain the array of integers \a x to be all equal */ predicate all_equal(array[$X] of var int: x) = all_equal_int(array1d(x)); /** @group globals.alldifferent Constrain the array of sets of integers \a x to be all equal */ predicate all_equal(array[$X] of var set of int: x) = all_equal_set(array1d(x)); libminizinc-2.4.2/share/minizinc/std/all_equal_int.mzn000066400000000000000000000010501360574160400231030ustar00rootroot00000000000000include "fzn_all_equal_int.mzn"; include "fzn_all_equal_int_reif.mzn"; %-----------------------------------------------------------------------------% % Constrains the array of objects 'x' to be all equal. %-----------------------------------------------------------------------------% predicate all_equal_int(array[int] of var int: x) = if length(x) <= 1 then true else fzn_all_equal_int(x) endif; predicate all_equal_int_reif(array[int] of var int: x, var bool: b) = if length(x) <= 1 then b=true else fzn_all_equal_int_reif(x,b) endif; libminizinc-2.4.2/share/minizinc/std/all_equal_set.mzn000066400000000000000000000010651360574160400231120ustar00rootroot00000000000000include "fzn_all_equal_set.mzn"; include "fzn_all_equal_set_reif.mzn"; %-----------------------------------------------------------------------------% % Constrains the array of objects 'x' to be all equal. %-----------------------------------------------------------------------------% predicate all_equal_set(array[int] of var set of int: x) = if length(x) <=1 then true else fzn_all_equal_set(x) endif; predicate all_equal_set_reif(array[int] of var set of int: x, var bool: b) = if length(x) <= 1 then b=true else fzn_all_equal_set_reif(x,b) endif; libminizinc-2.4.2/share/minizinc/std/alldifferent.mzn000066400000000000000000000002431360574160400227340ustar00rootroot00000000000000% The actual definitions are in all_different.mzn. % This file is used to handle the case where users include % "alldifferent.mzn"; % include "all_different.mzn"; libminizinc-2.4.2/share/minizinc/std/alldifferent_except_0.mzn000066400000000000000000000007311360574160400245250ustar00rootroot00000000000000include "fzn_alldifferent_except_0.mzn"; include "fzn_alldifferent_except_0_reif.mzn"; /** @group globals.alldifferent Constrain the array of integers \a vs to be all different except those elements that are assigned the value 0. */ predicate alldifferent_except_0(array[$X] of var int: vs) = fzn_alldifferent_except_0(array1d(vs)); predicate alldifferent_except_0_reif(array[$X] of var int: vs, var bool: b) = fzn_alldifferent_except_0_reif(array1d(vs),b); libminizinc-2.4.2/share/minizinc/std/alternative.mzn000066400000000000000000000017221360574160400226160ustar00rootroot00000000000000include "fzn_alternative.mzn"; include "fzn_alternative_reif.mzn"; /** @group globals.scheduling Alternative constraint for optional tasks. Task (\a s0,\a d0) spans the optional tasks (\a s[\p i],\a d[\p i]) in the array arguments and at most one can occur */ predicate alternative(var opt int: s0, var int: d0, array[int] of var opt int: s, array[int] of var int: d) = assert(index_set(s) = index_set(d), "alternative: index sets of third and fourth argument must be identical", fzn_alternative(s0, d0, s, d) ); predicate alternative_reif(var opt int: s0, var int: d0, array[int] of var opt int: s, array[int] of var int: d, var bool: b) = assert(index_set(s) = index_set(d), "alternative: index sets of third and fourth argument must be identical", fzn_alternative_reif(s0, d0, s, d, b) ); libminizinc-2.4.2/share/minizinc/std/among.mzn000066400000000000000000000005761360574160400214070ustar00rootroot00000000000000include "fzn_among.mzn"; include "fzn_among_reif.mzn"; /** @group globals.counting Requires exactly \a n variables in \a x to take one of the values in \a v. */ predicate among(var int: n, array[int] of var int: x, set of int: v) = fzn_among(n, x, v); predicate among_reif(var int: n, array[int] of var int: x, set of int: v, var bool: b) = fzn_among_reif(n, x, v, b); libminizinc-2.4.2/share/minizinc/std/among_fn.mzn000066400000000000000000000005101360574160400220560ustar00rootroot00000000000000include "among.mzn"; /** @group globals.counting Returns the number of variables in \a x that take one of the values in \a v. */ function var int: among(array[int] of var int:x, set of int:v) :: promise_total = let { var 0..length(x): n ::is_defined_var; constraint among(n,x,v) ::defines_var(n); } in n; libminizinc-2.4.2/share/minizinc/std/analyse_all_different.mzn000066400000000000000000000001021360574160400246010ustar00rootroot00000000000000predicate analyse_all_different(array[int] of var int: x) = true; libminizinc-2.4.2/share/minizinc/std/arg_max.mzn000066400000000000000000000050331360574160400217150ustar00rootroot00000000000000include "arg_max_int.mzn"; include "arg_max_bool.mzn"; include "arg_max_float.mzn"; /** @group globals Returns the index of the maximum value in the array \a x. When breaking ties the least index is returned. */ function var $$E: arg_max(array[$$E] of var int: x) = let { constraint length(x) > 0; } in arg_max_total(x); /** @group globals Returns the index of the maximum value in the array \a x. When breaking ties the least index is returned. */ function var $$E: arg_max(array[$$E] of var bool: x) = let { constraint length(x) > 0; } in arg_max_total(x); /** @group globals Returns the index of the maximum value in the array \a x. When breaking ties the least index is returned. */ function var $$E: arg_max(array[$$E] of var float: x) = let { constraint length(x) > 0; } in arg_max_total(x); function var $$E: arg_max_total(array[$$E] of var int: x) :: promise_total = if length(x) = 0 then 0 else let { var min(index_set(x)) .. max(index_set(x)): i; constraint maximum_arg_int(x, i); } in i endif; function var $$E: arg_max_total(array[$$E] of var bool: x) :: promise_total = if length(x) = 0 then 0 else let { var min(index_set(x)) .. max(index_set(x)): i; constraint maximum_arg_bool(x, i); } in i endif; function var $$E: arg_max_total(array[$$E] of var float: x) :: promise_total = if length(x) = 0 then 0 else let { var min(index_set(x)) .. max(index_set(x)): i; constraint maximum_arg_float(x, i); } in i endif; /** @group globals Constrain \a i to be the index of the maximum value in the array \a x. When breaking ties the least index is returned. Assumption: |\a x| > 0 */ predicate maximum_arg(array[int] of var int: x, var int: i) = maximum_arg_int(x, i); /** @group globals Constrain \a i to be the index of the maximum value in the array \a x. When breaking ties the least index is returned. Assumption: |\a x| > 0 */ predicate maximum_arg(array[int] of var bool: x, var int: i) = maximum_arg_bool(x, i); /** @group globals Constrain \a i to be the index of the maximum value in the array \a x. When breaking ties the least index is returned. Assumption: |\a x| > 0 */ predicate maximum_arg(array[int] of var float: x, var int: i) = maximum_arg_float(x, i); libminizinc-2.4.2/share/minizinc/std/arg_max_bool.mzn000066400000000000000000000003641360574160400227320ustar00rootroot00000000000000include "fzn_arg_max_bool.mzn"; predicate maximum_arg_bool(array[int] of var bool: x, var int: i) = fzn_maximum_arg_bool(x, i); predicate maximum_arg_bool_reif(array[int] of var bool: x, var int: i, var bool: b) = b <-> i=arg_max(x); libminizinc-2.4.2/share/minizinc/std/arg_max_float.mzn000066400000000000000000000003741360574160400231050ustar00rootroot00000000000000include "fzn_arg_max_float.mzn"; predicate maximum_arg_float(array[int] of var float: x, var int: i) = fzn_maximum_arg_float(x, i); predicate maximum_arg_float_reif(array[int] of var float: x, var int: i, var bool: b) = b <-> i=arg_max(x); libminizinc-2.4.2/share/minizinc/std/arg_max_int.mzn000066400000000000000000000003601360574160400225650ustar00rootroot00000000000000include "fzn_arg_max_int.mzn"; predicate maximum_arg_int(array[int] of var int: x, var int: i) = fzn_maximum_arg_int(x, i); predicate maximum_arg_int_reif(array[int] of var int: x, var int: i, var bool: b) = b <-> i=arg_max(x); libminizinc-2.4.2/share/minizinc/std/arg_min.mzn000066400000000000000000000050351360574160400217150ustar00rootroot00000000000000include "arg_min_int.mzn"; include "arg_min_bool.mzn"; include "arg_min_float.mzn"; /** @group globals Returns the index of the minimum value in the array \a x. When breaking ties the least index is returned. */ function var $$E: arg_min(array[$$E] of var int: x) = let { constraint length(x) > 0; } in arg_min_total(x); /** @group globals Returns the index of the minimum value in the array \a x. When breaking ties the least index is returned. */ function var $$E: arg_min(array[$$E] of var bool: x) = let { constraint length(x) > 0; } in arg_min_total(x); /** @group globals Returns the index of the minimum value in the array \a x. When breaking ties the least index is returned. */ function var $$E: arg_min(array[$$E] of var float: x) = let { constraint length(x) > 0; } in arg_min_total(x); function var $$E: arg_min_total(array[$$E] of var int: x) :: promise_total = if length(x) = 0 then 0 else let { var min(index_set(x)) .. max(index_set(x)): i; constraint minimum_arg_int(x, i); } in i endif; function var $$E: arg_min_total(array[$$E] of var bool: x) :: promise_total = if length(x) = 0 then 0 else let { var min(index_set(x)) .. max(index_set(x)): i; constraint minimum_arg_bool(x, i); } in i endif; function var $$E: arg_min_total(array[$$E] of var float: x) :: promise_total = if length(x) = 0 then 0 else let { var min(index_set(x)) .. max(index_set(x)): i; constraint minimum_arg_float(x, i); } in i endif; /** @group globals Constrain \a i to be the index of the minimum value in the array \a x. When breaking ties the least index is returned. Assumption: |\a x| > 0 */ predicate minimum_arg(array[int] of var int: x, var int: i) = minimum_arg_int(x, i); /** @group globals Constrain \a i to be the index of the minimum value in the array \a x. When breaking ties the least index is returned. Assumption: |\a x| > 0 */ predicate minimum_arg(array[int] of var bool: x, var int: i) = minimum_arg_bool(x, i); /** @group globals Constrain \a i to be the index of the minimum value in the array \a x. When breaking ties the least index is returned. Assumption: |\a x| > 0 */ predicate minimum_arg(array[int] of var float: x, var int: i) = minimum_arg_float(x, i); libminizinc-2.4.2/share/minizinc/std/arg_min_bool.mzn000066400000000000000000000003661360574160400227320ustar00rootroot00000000000000include "fzn_arg_min_bool.mzn"; predicate minimum_arg_bool(array[int] of var bool: x, var int: i) = fzn_minimum_arg_bool(x, i); predicate minimum_arg_bool_reif(array[int] of var bool: x, var int: i, var bool: b) = b <-> i=arg_min(x); libminizinc-2.4.2/share/minizinc/std/arg_min_float.mzn000066400000000000000000000003731360574160400231020ustar00rootroot00000000000000include "fzn_arg_min_float.mzn"; predicate minimum_arg_float(array[int] of var float: x, var int: i) = fzn_minimum_arg_float(x, i); predicate minimum_arg_float_reif(array[int] of var float: x, var int: i, var bool: b) = b <-> i=arg_min(x); libminizinc-2.4.2/share/minizinc/std/arg_min_int.mzn000066400000000000000000000003571360574160400225710ustar00rootroot00000000000000include "fzn_arg_min_int.mzn"; predicate minimum_arg_int(array[int] of var int: x, var int: i) = fzn_minimum_arg_int(x, i); predicate minimum_arg_int_reif(array[int] of var int: x, var int: i, var bool: b) = b <-> i=arg_min(x); libminizinc-2.4.2/share/minizinc/std/arg_sort.mzn000066400000000000000000000042721360574160400221230ustar00rootroot00000000000000include "arg_sort_int.mzn"; include "arg_sort_float.mzn"; include "analyse_all_different.mzn"; /** @group globals.sort Returns the permutation \a p which causes \a x to be in sorted order hence \a x[\a p[\p i]] <= \a x[\a p[\p i+1]]. The permutation is the stable sort hence \a x[\a p[\p i]] = \a x[\a p[\p i+1]] \(\rightarrow\) \a p[\p i] < \a p[\p i+1]. */ function array[int] of var int: arg_sort(array[int] of var int:x) :: promise_total = if length(x) = 0 then [] else let { int: l = min(index_set(x)); int: u = max(index_set(x)); array[1..u-l+1] of var l..u: p; constraint analyse_all_different(p); constraint arg_sort_int(x,p); } in p endif; /** @group globals.sort Returns the permutation \a p which causes \a x to be in sorted order hence \a x[\a p[\p i]] <= \a x[\a p[\p i+1]]. The permutation is the stable sort hence \a x[\a p[\p i]] = \a x[\a p[\p i+1]] \(\rightarrow\) \a p[\p i] < \a p[\p i+1]. */ function array[int] of var int: arg_sort(array[int] of var float:x) :: promise_total = if length(x) = 0 then [] else let { int: l = min(index_set(x)); int: u = max(index_set(x)); array[1..u-l+1] of var l..u: p; constraint analyse_all_different(p); constraint arg_sort_float(x,p); } in p endif; /** @group globals.sort Constrains \a p to be the permutation which causes \a x to be in sorted order hence \a x[\a p[\p i]] <= \a x[\a p[\p i+1]]. The permutation is the stable sort hence \a x[\a p[\p i]] = \a x[\a p[\p i+1]] \(\rightarrow\) \a p[\p i] < \a p[\p i+1]. */ predicate arg_sort(array[int] of var int:x, array[int] of var int:p) = fzn_arg_sort_int(x,p); /** @group globals.sort Constrains \a p to be the permutation which causes \a x to be in sorted order hence \a x[\a p[\p i]] <= \a x[\a p[\p i+1]]. The permutation is the stable sort hence \a x[\a p[\p i]] = \a x[\a p[\p i+1]] \(\rightarrow\) \a p[\p i] < \a p[\p i+1]. */ predicate arg_sort(array[int] of var float:x, array[int] of var int:p) = arg_sort_float(x,p); libminizinc-2.4.2/share/minizinc/std/arg_sort_float.mzn000066400000000000000000000012221360574160400233000ustar00rootroot00000000000000include "fzn_arg_sort_float.mzn"; include "fzn_arg_sort_float_reif.mzn"; predicate arg_sort_float(array[int] of var float:x, array[int] of var int:p) = assert(index_set(p) = 1..length(x), "arg_sort_float: second argument must have index 1..length(first argument)", fzn_arg_sort_float(x, p) ); predicate arg_sort_float_reif(array[int] of var float:x, array[int] of var int:p, var bool: b) = assert(index_set(p) = 1..length(x), "arg_sort_float: second argument must have index 1..length(first argument)", fzn_arg_sort_float_reif(x, p, b) ); libminizinc-2.4.2/share/minizinc/std/arg_sort_int.mzn000066400000000000000000000011501360574160400227650ustar00rootroot00000000000000include "fzn_arg_sort_int.mzn"; include "fzn_arg_sort_int_reif.mzn"; predicate arg_sort_int(array[int] of var int:x, array[int] of var int:p) = assert(index_set(p) = 1..length(x), "arg_sort_int: second argument must have index 1..length(first argument)", fzn_arg_sort_int(x, p) ); predicate arg_sort_int(array[int] of var int:x, array[int] of var int:p, var bool:b) = assert(index_set(p) = 1..length(x), "arg_sort_int: second argument must have index 1..length(first argument)", fzn_arg_sort_int_reif(x, p, b) ); libminizinc-2.4.2/share/minizinc/std/at_least.mzn000066400000000000000000000013501360574160400220710ustar00rootroot00000000000000include "at_least_int.mzn"; include "at_least_set.mzn"; /** @group globals.deprecated Requires at least \a n variables in \a x to take the value \a v. This constraint is deprecated. Use count(i in x)(i=v) >= n instead. */ predicate at_least(int: n, array[int] of var int: x, int: v) = at_least_int(n, x, v); /** @group globals.counting Requires at least \a n variables in \a x to take the value \a v. */ predicate at_least(int: n, array[int] of var set of int: x, set of int: v) = at_least_set(n, x, v); % Synonyms for the above. predicate atleast(int: n, array[int] of var int: x, int: v) = at_least_int(n, x, v); predicate atleast(int: n, array[int] of var set of int: x, set of int: v) = at_least_set(n, x, v); libminizinc-2.4.2/share/minizinc/std/at_least.mzn.deprecated.mzn000066400000000000000000000002341360574160400247730ustar00rootroot00000000000000predicate at_least(int: n, array[int] of var int: x, int: v) ::mzn_deprecated("2.4.0","https://www.minizinc.org/doc-2.4.0/en/lib-globals.html#deprecated"); libminizinc-2.4.2/share/minizinc/std/at_least_int.mzn000066400000000000000000000010061360574160400227410ustar00rootroot00000000000000include "fzn_at_least_int.mzn"; include "fzn_at_least_int_reif.mzn"; %-----------------------------------------------------------------------------% % Requires at least 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate at_least_int(int: n, array[int] of var int: x, int: v) = fzn_at_least_int(n, x, v); predicate at_least_int_reif(int: n, array[int] of var int: x, int: v, var bool: b) = fzn_at_least_int_reif(n, x, v, b); libminizinc-2.4.2/share/minizinc/std/at_least_set.mzn000066400000000000000000000010421360574160400227420ustar00rootroot00000000000000include "fzn_at_least_set.mzn"; include "fzn_at_least_set_reif.mzn"; %-----------------------------------------------------------------------------% % Requires at least 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate at_least_set(int: n, array[int] of var set of int: x, set of int: v) = fzn_at_least_set(n, x, v); predicate at_least_set_reif(int: n, array[int] of var set of int: x, set of int: v, var bool: b) = fzn_at_least_set_reif(n, x, v, b); libminizinc-2.4.2/share/minizinc/std/at_most.mzn000066400000000000000000000013341360574160400217450ustar00rootroot00000000000000include "at_most_int.mzn"; include "at_most_set.mzn"; /** @group globals.deprecated Requires at most \a n variables in \a x to take the value \a v. This constraint is deprecated. Use count(i in x)(i=v) <= n instead. */ predicate at_most(int: n, array[int] of var int: x, int: v) = at_most_int(n, x, v); /** @group globals.counting Requires at most \a n variables in \a x to take the value \a v. */ predicate at_most(int: n, array[int] of var set of int: x, set of int: v) = at_most_set(n, x, v); % Synonyms for the above. predicate atmost(int: n, array[int] of var int: x, int: v) = at_most_int(n, x, v); predicate atmost(int: n, array[int] of var set of int: x, set of int: v) = at_most_set(n, x, v); libminizinc-2.4.2/share/minizinc/std/at_most.mzn.deprecated.mzn000066400000000000000000000002331360574160400246440ustar00rootroot00000000000000predicate at_most(int: n, array[int] of var int: x, int: v) ::mzn_deprecated("2.4.0","https://www.minizinc.org/doc-2.4.0/en/lib-globals.html#deprecated"); libminizinc-2.4.2/share/minizinc/std/at_most1.mzn000066400000000000000000000006711360574160400220310ustar00rootroot00000000000000include "fzn_at_most1.mzn"; include "fzn_at_most1_reif.mzn"; /** @group globals.counting Requires that each pair of sets in \a s overlap in at most one element. */ predicate at_most1(array[int] of var set of int: s) = fzn_at_most1(s); predicate at_most1_reif(array[int] of var set of int: s, var bool: b) = fzn_at_most1_reif(s, b); % Synonym for the above. predicate atmost1(array[int] of var set of int: s) = fzn_at_most1(s); libminizinc-2.4.2/share/minizinc/std/at_most_int.mzn000066400000000000000000000007771360574160400226310ustar00rootroot00000000000000include "fzn_at_most_int.mzn"; include "fzn_at_most_int_reif.mzn"; %-----------------------------------------------------------------------------% % Requires at most 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate at_most_int(int: n, array[int] of var int: x, int: v) = fzn_at_most_int(n, x, v); predicate at_most_int_reif(int: n, array[int] of var int: x, int: v, var bool: b) = fzn_at_most_int_reif(n, x, v, b); libminizinc-2.4.2/share/minizinc/std/at_most_set.mzn000066400000000000000000000010341360574160400226150ustar00rootroot00000000000000include "fzn_at_most_set.mzn"; include "fzn_at_most_set_reif.mzn"; %-----------------------------------------------------------------------------% % Requires at most 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate at_most_set(int: n, array[int] of var set of int: x, set of int: v) = fzn_at_most_set(n, x, v); predicate at_most_set_reif(int: n, array[int] of var set of int: x, set of int: v, var bool: b) = fzn_at_most_set_reif(n, x, v, b); libminizinc-2.4.2/share/minizinc/std/atleast.mzn000066400000000000000000000002241360574160400217310ustar00rootroot00000000000000% The actual definitions are in at_least.mzn. % This file is used to handle the case where users include % "atleast.mzn"; % include "at_least.mzn"; libminizinc-2.4.2/share/minizinc/std/atmost.mzn000066400000000000000000000002201360574160400215770ustar00rootroot00000000000000% The actual definitions are in atmost.mzn. % This file is used to handle the case where users include % "atmost.mzn"; % include "at_most.mzn"; libminizinc-2.4.2/share/minizinc/std/atmost1.mzn000066400000000000000000000002241360574160400216640ustar00rootroot00000000000000% The actual definitions are in at_most1.mzn. % This file is used to handle the case where users include % "atmost1.mzn"; % include "at_most1.mzn"; libminizinc-2.4.2/share/minizinc/std/bin_packing.mzn000066400000000000000000000025211360574160400225420ustar00rootroot00000000000000include "fzn_bin_packing.mzn"; include "fzn_bin_packing_reif.mzn"; /** @group globals.packing Requires that each item \p i with weight \a w[\p i], be put into \a bin[\p i] such that the sum of the weights of the items in each bin does not exceed the capacity \a c. Assumptions: - forall \p i, \a w[\p i] >=0 - \a c >=0 */ predicate bin_packing(int: c, array[int] of var int: bin, array[int] of int: w) = assert(index_set(bin) == index_set(w), "bin_packing: the bin and weight arrays must have identical index sets", assert(lb_array(w) >= 0, "bin_packing: the weights must be non-negative", assert(c >= 0, "bin_packing: capacity must be non-negative", fzn_bin_packing(c, bin, w) ))); predicate bin_packing_reif(int: c, array[int] of var int: bin, array[int] of int: w, var bool: b) = assert(index_set(bin) == index_set(w), "bin_packing: the bin and weight arrays must have identical index sets", assert(lb_array(w) >= 0, "bin_packing: the weights must be non-negative", assert(c >= 0, "bin_packing: capacity must be non-negative", fzn_bin_packing_reif(c, bin, w, b) ))); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/bin_packing_capa.mzn000066400000000000000000000030211360574160400235220ustar00rootroot00000000000000include "fzn_bin_packing_capa.mzn"; include "fzn_bin_packing_capa_reif.mzn"; /** @group globals.packing Requires that each item \p i with weight \a w[\p i], be put into \a bin[\p i] such that the sum of the weights of the items in each bin \p b does not exceed the capacity \a c[\p b]. Assumptions: - forall \p i, \a w[\p i] >=0 - forall \p b, \a c[\p b] >=0 */ predicate bin_packing_capa(array[int] of int: c, array[int] of var int: bin, array[int] of int: w) = assert(index_set(bin) = index_set(w), "bin_packing_capa: the bin and weight arrays must have identical index sets", assert(lb_array(w) >= 0, "bin_packing_capa: the weights must be non-negative", assert(lb_array(c) >= 0, "bin_packing_capa: the capacities must be non-negative", fzn_bin_packing_capa(c, bin, w) ))); predicate bin_packing_capa_reif(array[int] of int: c, array[int] of var int: bin, array[int] of int: w, var bool: b) = assert(index_set(bin) = index_set(w), "bin_packing_capa: the bin and weight arrays must have identical index sets", assert(lb_array(w) >= 0, "bin_packing_capa: the weights must be non-negative", assert(lb_array(c) >= 0, "bin_packing_capa: the capacities must be non-negative", fzn_bin_packing_capa_reif(c, bin, w, b) ))); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/bin_packing_load.mzn000066400000000000000000000024671360574160400235520ustar00rootroot00000000000000include "fzn_bin_packing_load.mzn"; include "fzn_bin_packing_load_reif.mzn"; /** @group globals.packing Requires that each item \p i with weight \a w[\p i], be put into \a bin[\p i] such that the sum of the weights of the items in each bin \p b is equal to \a load[\p b]. Assumptions: - forall \p i, \a w[\p i] >=0 */ predicate bin_packing_load(array[int] of var int: load, array[int] of var int: bin, array[int] of int: w) = assert(index_set(bin) == index_set(w), "bin_packing_load: the bin and weight arrays must have identical index sets", assert(lb_array(w) >= 0, "bin_packing_load: the weights must be non-negative", fzn_bin_packing_load(load, bin, w) )); predicate bin_packing_load_reif(array[int] of var int: load, array[int] of var int: bin, array[int] of int: w, var bool: b) = assert(index_set(bin) == index_set(w), "bin_packing_load: the bin and weight arrays must have identical index sets", assert(lb_array(w) >= 0, "bin_packing_load: the weights must be non-negative", fzn_bin_packing_load_reif(load, bin, w, b) )); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/bin_packing_load_fn.mzn000066400000000000000000000011301360574160400242170ustar00rootroot00000000000000include "bin_packing_load.mzn"; /** @group globals.packing Returns the load of each bin resulting from packing each item \p i with weight \a w[\p i] into \a bin[\p i], where the load is defined as the sum of the weights of the items in each bin. Assumptions: - forall \p i, \a w[\p i] >=0 */ function array[int] of var int: bin_packing_load(array[int] of var int: bin, array[int] of int: w) :: promise_total = let { array[dom_bounds_array(bin)] of var 0..sum(w): load; constraint bin_packing_load(load,bin,w); } in load; libminizinc-2.4.2/share/minizinc/std/bounded_path.mzn000066400000000000000000000133551360574160400227410ustar00rootroot00000000000000/** @group globals.graph Constrains the subgraph \a ns and \a es of a given directed graph to be a path from \a s to \a t of weight \a K. @param N: the number of nodes in the given graph @param E: the number of edges in the given graph @param from: the leaving node 1..\a N for each edge @param to: the entering node 1..\a N for each edge @param w: the weight of each edge @param s: the source node (which may be variable) @param t: the dest node (which may be variable) @param ns: a Boolean for each node whether it is in the subgraph @param es: a Boolean for each edge whether it is in the subgraph @param K: the cost of the path */ predicate bounded_dpath(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of int: w, var int: s, var int: t, array[int] of var bool: ns, array[int] of var bool: es, var int: K) = assert(index_set(from) = 1..E,"bounded_dpath: index set of from must be 1..\(E)") /\ assert(index_set(to) = 1..E,"bounded_dpath: index set of to must be 1..\(E)") /\ assert(index_set(ns) = 1..N,"bounded_dpath: index set of ns must be 1..\(N)") /\ assert(index_set(es) = 1..E,"bounded_dpath: index set of es must be 1..\(E)") /\ assert(index_set(w) = 1..E,"bounded_dpath: index set of w must be 1..\(E)") /\ fzn_bounded_dpath(N,E,from,to,w,s,t,ns,es,K); /** @group globals.graph Constrains the subgraph \a ns and \a es of a given directed graph to be a path from \a s to \a t of weight \a K. @param from: the leaving node for each edge @param to: the entering node for each edge @param w: the weight of each edge @param s: the source node (which may be variable) @param t: the dest node (which may be variable) @param ns: a Boolean for each node whether it is in the subgraph @param es: a Boolean for each edge whether it is in the subgraph @param K: the cost of the path */ predicate bounded_dpath(array[int] of $$N: from, array[int] of $$N: to, array[int] of int: w, var $$N: s, var $$N: t, array[$$N] of var bool: ns, array[int] of var bool: es, var int: K) = assert(index_set(from) = index_set(to),"bounded_dpath: index set of from and to must be identical") /\ assert(index_set(from) = index_set(es),"bounded_dpath: index set of from and es must be identical") /\ assert(index_set(w) = index_set(es),"bounded_dpath: index set of w and es must be identical") /\ assert(dom_array(from) subset index_set(ns),"bounded_dpath: nodes in from must be in index set of ns") /\ assert(dom_array(from) subset index_set(ns),"bounded_dpath: nodes in to must be in index set of ns") /\ fzn_bounded_dpath(from,to,w,s,t,ns,es,K); /** @group globals.graph Constrains the subgraph \a ns and \a es of a given undirected graph to be a path from \a s to \a t of weight \a K. @param N: the number of nodes in the given graph @param E: the number of edges in the given graph @param from: the leaving node 1..\a N for each edge @param to: the entering node 1..\a N for each edge @param w: the weight of each edge @param s: the source node (which may be variable) @param t: the dest node (which may be variable) @param ns: a Boolean for each node whether it is in the subgraph @param es: a Boolean for each edge whether it is in the subgraph @param K: the cost of the path */ predicate bounded_path(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of int: w, var int: s, var int: t, array[int] of var bool: ns, array[int] of var bool: es, var int: K) = assert(index_set(from) = 1..E,"bounded_path: index set of from must be 1..\(E)") /\ assert(index_set(to) = 1..E,"bounded_path: index set of to must be 1..\(E)") /\ assert(index_set(ns) = 1..N,"bounded_path: index set of ns must be 1..\(N)") /\ assert(index_set(es) = 1..E,"bounded_path: index set of es must be 1..\(E)") /\ assert(index_set(w) = 1..E,"bounded_path: index set of w must be 1..\(E)") /\ fzn_bounded_path(N,E,from,to,w,s,t,ns,es,K); /** @group globals.graph Constrains the subgraph \a ns and \a es of a given undirected graph to be a path from \a s to \a t of weight \a K. @param from: the leaving node for each edge @param to: the entering node for each edge @param w: the weight of each edge @param s: the source node (which may be variable) @param t: the dest node (which may be variable) @param ns: a Boolean for each node whether it is in the subgraph @param es: a Boolean for each edge whether it is in the subgraph @param K: the cost of the path */ predicate bounded_path(array[int] of $$N: from, array[int] of $$N: to, array[int] of int: w, var $$N: s, var $$N: t, array[$$N] of var bool: ns, array[int] of var bool: es, var int: K) = assert(index_set(from) = index_set(to),"bounded_path: index set of from and to must be identical") /\ assert(index_set(from) = index_set(es),"bounded_path: index set of from and es must be identical") /\ assert(index_set(w) = index_set(es),"bounded_path: index set of w and es must be identical") /\ assert(dom_array(from) subset index_set(ns),"bounded_path: nodes in from must be in index set of ns") /\ assert(dom_array(from) subset index_set(ns),"bounded_path: nodes in to must be in index set of ns") /\ fzn_bounded_path(from,to,w,s,t,ns,es,K); include "fzn_bounded_path_int.mzn"; include "fzn_bounded_path_int_reif.mzn"; include "fzn_bounded_path_enum.mzn"; include "fzn_bounded_path_enum_reif.mzn"; include "fzn_bounded_dpath_int.mzn"; include "fzn_bounded_dpath_int_reif.mzn"; include "fzn_bounded_dpath_enum.mzn"; include "fzn_bounded_dpath_enum_reif.mzn"; %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/builtins.mzn000066400000000000000000004445561360574160400221510ustar00rootroot00000000000000include "flatzinc_builtins.mzn"; /*** @groupdef builtins Builtins These functions and predicates define built-in operations of the MiniZinc language. */ /*** @groupdef builtins.compare Comparison Builtins These builtins implement comparison operations. */ /** @group builtins.compare Return if \a x is less than \a y */ function bool: '<'( $T: x, $T: y); /** @group builtins.compare Return if \a x is less than \a y */ function var bool: '<'(var $T: x,var $T: y); /** @group builtins.compare Return if \a x is greater than \a y */ function bool: '>'( $T: x, $T: y); /** @group builtins.compare Return if \a x is greater than \a y */ function var bool: '>'(var $T: x,var $T: y); /** @group builtins.compare Return if \a x is less than or equal to \a y */ function bool: '<='( $T: x, $T: y); /** @group builtins.compare Return if \a x is less than or equal to \a y */ function var bool: '<='(var $T: x, var $T: y); /** @group builtins.compare Return if \a x is greater than or equal to \a y */ function bool: '>='( $T: x, $T: y); /** @group builtins.compare Return if \a x is greater than or equal to \a y */ function var bool: '>='(var $T: x,var $T: y); /** @group builtins.compare Return if \a x is equal to \a y */ function bool: '='( $T: x, $T: y); /** @group builtins.compare Return if \a x is equal to \a y */ function bool: '='(opt $T: x, opt $T: y); /** @group builtins.compare Return if \a x is equal to \a y */ function var bool: '='(var $T: x,var $T: y); /** @group builtins.compare Return if \a x is equal to \a y */ function var bool: '='(var opt $T: x,var opt $T: y); /** @group builtins.compare Return if \a x is not equal to \a y */ function bool: '!='( $T: x, $T: y); /** @group builtins.compare Return if \a x is not equal to \a y */ function var bool: '!='(var $T: x, var $T: y); % Special case comparison operators for integer variable and float constant function var bool: '<='(var int: x, float: y) = (x <= floor(y)); function var bool: '>='(var int: x, float: y) = (x >= ceil(y)); function var bool: '<='(float: x, var int: y) = (y >= ceil(x)); function var bool: '>='(float: x, var int: y) = (y <= floor(x)); function var bool: '<'(var int: x, float: y) = (x <= ceil(y)-1); function var bool: '>'(float: x, var int: y) = (y <= ceil(x)-1); function var bool: '>'(var int: x, float: y) = (x >= floor(y)+1); function var bool: '<'(float: x, var int: y) = (y >= floor(x)+1); function var bool: '='(var int: x, float: y) = if ceil(y)=floor(y) then x=ceil(y) else false endif; function var bool: '='(float: x, var int: y) = if ceil(x)=floor(x) then y=ceil(x) else false endif; function var bool: '!='(var int: x, float: y) = if ceil(y)=floor(y) then x != ceil(y) else true endif; function var bool: '!='(float: x, var int: y) = if ceil(x)=floor(x) then y != ceil(x) else true endif; function bool: '<='(int: x, float: y) = (x <= floor(y)); function bool: '>='(int: x, float: y) = (x >= ceil(y)); function bool: '<='(float: x, int: y) = (y >= ceil(x)); function bool: '>='(float: x, int: y) = (y <= floor(x)); function bool: '<'(int: x, float: y) = (x <= ceil(y)-1); function bool: '>'(float: x, int: y) = (y <= ceil(x)-1); function bool: '>'(int: x, float: y) = (x >= floor(y)+1); function bool: '<'(float: x, int: y) = (y >= floor(x)+1); function bool: '='(int: x, float: y) = if ceil(y)=floor(y) then x=ceil(y) else false endif; function bool: '='(float: x, int: y) = if ceil(x)=floor(x) then y=ceil(x) else false endif; function bool: '!='(int: x, float: y) = if ceil(y)=floor(y) then x != ceil(y) else true endif; function bool: '!='(float: x, int: y) = if ceil(x)=floor(x) then y != ceil(x) else true endif; /** @group builtins.compare Return if array \a x is lexicographically smaller than array \a y */ function bool: '<'(array[$U] of $T: x,array[$U] of $T: y); /** @group builtins.compare Return if array \a x is lexicographically smaller than array \a y */ function var bool: '<'(array[$U] of var $T: x,array[$U] of var $T: y); /** @group builtins.compare Return if array \a x is lexicographically greater than array \a y */ function bool: '>'(array[$U] of $T: x,array[$U] of $T: y); /** @group builtins.compare Return if array \a x is lexicographically greater than array \a y */ function var bool: '>'(array[$U] of var $T: x,array[$U] of var $T: y); /** @group builtins.compare Return if array \a x is lexicographically smaller than or equal to array \a y */ function bool: '<='(array[$U] of $T: x,array[$U] of $T: y); /** @group builtins.compare Return if array \a x is lexicographically smaller than or equal to array \a y */ function var bool: '<='(array[$U] of var $T: x,array[$U] of var $T: y); /** @group builtins.compare Return if array \a x is lexicographically greater than or equal to array \a y */ function bool: '>='(array[$U] of $T: x,array[$U] of $T: y); function var bool: '>='(array[$U] of var $T: x,array[$U] of var $T: y); /** @group builtins.compare Return if array \a x is equal to array \a y */ function bool: '='(array[$T] of int: x,array[$T] of int: y) = let { array[int] of int: xx = array1d(x); array[int] of int: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", forall (i in index_set(xx)) (xx[i]=yy[i]) ); /** @group builtins.compare Return if array \a x is equal to array \a y */ function var bool: '='(array[$T] of var int: x,array[$T] of var int: y) = let { array[int] of var int: xx = array1d(x); array[int] of var int: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", forall (i in index_set(xx)) (xx[i]=yy[i]) ); /** @group builtins.compare Return if array \a x is equal to array \a y */ function bool: '='(array[$T] of bool: x,array[$T] of bool: y) = let { array[int] of bool: xx = array1d(x); array[int] of bool: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", forall (i in index_set(xx)) (xx[i]=yy[i]) ); /** @group builtins.compare Return if array \a x is equal to array \a y */ function var bool: '='(array[$T] of var bool: x,array[$T] of var bool: y) = let { array[int] of var bool: xx = array1d(x); array[int] of var bool: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", forall (i in index_set(xx)) (xx[i]=yy[i]) ); /** @group builtins.compare Return if array \a x is equal to array \a y */ function bool: '='(array[$T] of set of int: x,array[$T] of set of int: y) = let { array[int] of set of int: xx = array1d(x); array[int] of set of int: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", forall (i in index_set(xx)) (xx[i]=yy[i]) ); /** @group builtins.compare Return if array \a x is equal to array \a y */ function var bool: '='(array[$T] of var set of int: x,array[$T] of var set of int: y) = let { array[int] of var set of int: xx = array1d(x); array[int] of var set of int: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", forall (i in index_set(xx)) (xx[i]=yy[i]) ); /** @group builtins.compare Return if array \a x is equal to array \a y */ function bool: '='(array[$T] of float: x,array[$T] of float: y) = let { array[int] of float: xx = array1d(x); array[int] of float: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", forall (i in index_set(xx)) (xx[i]=yy[i]) ); /** @group builtins.compare Return if array \a x is equal to array \a y */ function var bool: '='(array[$T] of var float: x,array[$T] of var float: y) = let { array[int] of var float: xx = array1d(x); array[int] of var float: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", forall (i in index_set(xx)) (xx[i]=yy[i]) ); /** @group builtins.compare Return if array \a x is not equal to array \a y */ function bool: '!='(array[$T] of int: x,array[$T] of int: y) = let { array[int] of int: xx = array1d(x); array[int] of int: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", exists (i in index_set(xx)) (xx[i]!=yy[i]) ); /** @group builtins.compare Return if array \a x is not equal to array \a y */ function var bool: '!='(array[$T] of var int: x,array[$T] of var int: y) = let { array[int] of var int: xx = array1d(x); array[int] of var int: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", exists (i in index_set(xx)) (xx[i]!=yy[i]) ); /** @group builtins.compare Return if array \a x is not equal to array \a y */ function bool: '!='(array[$T] of bool: x,array[$T] of bool: y) = let { array[int] of bool: xx = array1d(x); array[int] of bool: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", exists (i in index_set(xx)) (xx[i]!=yy[i]) ); /** @group builtins.compare Return if array \a x is not equal to array \a y */ function var bool: '!='(array[$T] of var bool: x,array[$T] of var bool: y) = let { array[int] of var bool: xx = array1d(x); array[int] of var bool: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", exists (i in index_set(xx)) (xx[i]!=yy[i]) ); /** @group builtins.compare Return if array \a x is not equal to array \a y */ function bool: '!='(array[$T] of set of int: x,array[$T] of set of int: y) = let { array[int] of set of int: xx = array1d(x); array[int] of set of int: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", exists (i in index_set(xx)) (xx[i]!=yy[i]) ); /** @group builtins.compare Return if array \a x is not equal to array \a y */ function var bool: '!='(array[$T] of var set of int: x,array[$T] of var set of int: y) = let { array[int] of var set of int: xx = array1d(x); array[int] of var set of int: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", exists (i in index_set(xx)) (xx[i]!=yy[i]) ); /** @group builtins.compare Return if array \a x is not equal to array \a y */ function bool: '!='(array[$T] of float: x,array[$T] of float: y) = let { array[int] of float: xx = array1d(x); array[int] of float: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", exists (i in index_set(xx)) (xx[i]!=yy[i]) ); /** @group builtins.compare Return if array \a x is not equal to array \a y */ function var bool: '!='(array[$T] of var float: x,array[$T] of var float: y) = let { array[int] of var float: xx = array1d(x); array[int] of var float: yy = array1d(y); } in assert(index_sets_agree(x,y), "array index sets do not match", exists (i in index_set(xx)) (xx[i]!=yy[i]) ); /*** @groupdef builtins.arithmetic Arithmetic Builtins These builtins implement arithmetic operations. */ /** @group builtins.arithmetic Return \a x + \a y */ function int: '+'( int: x, int: y); /** @group builtins.arithmetic Return \a x + \a y */ function var int: '+'(var int: x, var int: y); /** @group builtins.arithmetic Return \a x + \a y */ function float: '+'( float: x, float: y); /** @group builtins.arithmetic Return \a x + \a y */ function var float: '+'(var float: x,var float: y); /** @group builtins.arithmetic Return \a x - \a y */ function int: '-'( int: x, int: y); /** @group builtins.arithmetic Return \a x - \a y */ function var int: '-'(var int: x, var int: y); /** @group builtins.arithmetic Return \a x - \a y */ function float: '-'( float: x, float: y); /** @group builtins.arithmetic Return \a x - \a y */ function var float: '-'(var float: x,var float: y); /** @group builtins.arithmetic Return \a x * \a y */ function int: '*'( int: x, int: y); /** @group builtins.arithmetic Return \a x * \a y */ function var int: '*'(var int: x, var int: y); /** @group builtins.arithmetic Return \(\a x ^ {\a y}\) */ function int: '^'( int: x, int: y); /** @group builtins.arithmetic Return \(\a x ^ {\a y}\) */ function var int: '^'(var int: x, var int: y); /** @group builtins.arithmetic Return \a x * \a y */ function float: '*'( float: x, float: y); /** @group builtins.arithmetic Return \a x * \a y */ function var float: '*'(var float: x,var float: y); /** @group builtins.arithmetic Return \(\a x ^ {\a y}\) */ function float: '^'( float: x, float: y); /** @group builtins.arithmetic Return \(\a x ^ {\a y}\) */ function var float: '^'(var float: x,var float: y); /** @group builtins.arithmetic Return negative \a x */ function int: '-'( int: x); /** @group builtins.arithmetic Return negative \a x */ function var int: '-'(var int: x); /** @group builtins.arithmetic Return negative \a x */ function float: '-'( float: x); /** @group builtins.arithmetic Return negative \a x */ function var float: '-'(var float: x); /** @group builtins.arithmetic Return result of integer division \a x / \a y */ function int: 'div'(int: x,int: y); /** @group builtins.arithmetic Return result of integer division \a x / \a y */ function var int: 'div'(var int: x,var int: y) = if mzn_in_root_context(y) then div_t(x,y) elseif not (0 in dom(y)) then div_t(x,y) else let { constraint y != 0 } in div_mt(x,y) endif; /** @group builtins.arithmetic Return remainder of integer division \a x % \a y */ function int: 'mod'(int: x,int: y); /** @group builtins.arithmetic Return remainder of integer division \a x % \a y */ function var int: 'mod'(var int: x,var int: y) = if mzn_in_root_context(y) then mod_t(x,y) elseif not (0 in dom(y)) then mod_t(x,y) else let { constraint y != 0 } in mod_mt(x,y) endif; /** @group builtins.arithmetic Return result of floating point division \a x / \a y */ function float: '/'( float: x, float: y); /** @group builtins.arithmetic Return result of floating point division \a x / \a y */ function var float: '/'(var float: x,var float: y) = if mzn_in_root_context(y) then fldiv_t(x,y) elseif lb(y) > 0.0 \/ ub(y) < 0.0 then fldiv_t(x,y) else let { constraint y != 0.0 } in fldiv_mt(x,y) endif; /** @group builtins.arithmetic Return number of true elments in array \a x */ function int: count(array[$T] of bool: x) = sum([bool2int(y) | y in array1d(x)]); /** @group builtins.arithmetic Return number of true elments in array \a x */ function var int: count(array[$T] of var bool: x) = sum([bool2int(y) | y in array1d(x)]); /** @group builtins.arithmetic Return sum of elements in array \a x */ function int: sum(array[$T] of bool: x) = sum([bool2int(y)|y in array1d(x)]); /** @group builtins.arithmetic Return sum of elements in array \a x */ function var int: sum(array[$T] of var bool: x) = sum([bool2int(y)|y in array1d(x)]); /** @group builtins.arithmetic Return sum of elements in array \a x */ function int: sum(array[$T] of int: x); /** @group builtins.arithmetic Return sum of elements in array \a x */ function var int: sum(array[$T] of var int: x); /** @group builtins.arithmetic Return sum of elements in array \a x */ function float: sum(array[$T] of float: x); /** @group builtins.arithmetic Return sum of elements in array \a x */ function var float: sum(array[$T] of var float: x); /** @group builtins.arithmetic Return product of elements in array \a x */ function int: product(array[$T] of int: x); /** @group builtins.arithmetic Return product of elements in array \a x */ function var int: product(array[$T] of var int: x) = product_rec(array1d(x)); /** @group builtins.arithmetic Return product of elements in array \a x */ function float: product(array[$T] of float: x); /** @group builtins.arithmetic Return product of elements in array \a x */ function var float: product(array[$T] of var float: x) = product_rec(array1d(x)); /** @group builtins.arithmetic Return minimum of \a x and \a y */ function $T: min( $T: x, $T: y); /** @group builtins.arithmetic Return minimum of elements in array \a x */ function $T: min(array[$U] of par $T: x); /** @group builtins.arithmetic Return maximum of \a x and \a y */ function $T: max( $T: x, $T: y); /** @group builtins.arithmetic Return maximum of elements in array \a x */ function $T: max(array[$U] of $T: x); /** @group builtins.arithmetic Return minimum of elements in set \a x */ function $$E: min(set of $$E: x); /** @group builtins.arithmetic Return maximum of elements in set \a x */ function $$E: max(set of $$E: x); /** @group builtins.arithmetic Return maximum of \a x and \a y */ function var int: max(var int: x, var int: y) :: promise_total = let { var max(lb(x),lb(y))..max(ub(x),ub(y)): m ::is_defined_var; constraint int_max(x,y,m) ::defines_var(m); } in m; /** @group builtins.arithmetic Return maximum of elements in array \a x */ function var int: max(array[$U] of var int: x) = let { array[int] of var int: xx = array1d(x); constraint length(x) >= 1; } in max_t(xx); /** @group builtins.arithmetic Return minimum of \a x and \a y */ function var int: min(var int: x, var int: y) :: promise_total = let { var min(lb(x),lb(y))..min(ub(x),ub(y)): m ::is_defined_var; constraint int_min(x,y,m) ::defines_var(m); } in m; /** @group builtins.arithmetic Return minimum of elements in array \a x */ function var int: min(array[$U] of var int: x) = let { array[int] of var int: xx = array1d(x); constraint length(x) >= 1; } in min_t(xx); % Floating point min and max % TODO: add bounds reasoning /** @group builtins.arithmetic Return maximum of \a x and \a y */ function var float: max(var float: x, var float: y) :: promise_total = if has_bounds(x) /\ has_bounds(y) then let { var max(lb(x),lb(y))..max(ub(x),ub(y)): m ::is_defined_var; constraint float_max(x,y,m) ::defines_var(m); } in m else let { var float: m ::is_defined_var; constraint float_max(x,y,m) ::defines_var(m); } in m endif; /** @group builtins.arithmetic Return maximum of elements in array \a x */ function var float: max(array[$U] of var float: x) = let { array[int] of var float: xx = array1d(x); constraint length(x) >= 1; } in max_t(xx); /** @group builtins.arithmetic Return minimum of \a x and \a y */ function var float: min(var float: x, var float: y) :: promise_total = if has_bounds(x) /\ has_bounds(y) then let { var min(lb(x),lb(y))..min(ub(x),ub(y)): m ::is_defined_var; constraint float_min(x,y,m) ::defines_var(m); } in m else let { var float: m ::is_defined_var; constraint float_min(x,y,m) ::defines_var(m); } in m endif; /** @group builtins.arithmetic Return minimum of elements in array \a x */ function var float: min(array[$U] of var float: x) = let { array[int] of var float: xx = array1d(x); constraint length(x) >= 1; } in min_t(xx); /** @group builtins.arithmetic Returns the index of the minimum value in the array \a x. When breaking ties the least index is returned. */ function $$E: arg_min(array[$$E] of int: x); /** @group builtins.arithmetic Returns the index of the minimum value in the array \a x. When breaking ties the least index is returned. */ function $$E: arg_min(array[$$E] of float: x); /** @group builtins.arithmetic Returns the index of the maximum value in the array \a x. When breaking ties the least index is returned. */ function $$E: arg_max(array[$$E] of int: x); /** @group builtins.arithmetic Returns the index of the maximum value in the array \a x. When breaking ties the least index is returned. */ function $$E: arg_max(array[$$E] of float: x); /** @group builtins.arithmetic Return absolute value of \a x */ function int: abs(int: x); /** @group builtins.arithmetic Return absolute value of \a x */ function var int: abs(var int: x) :: promise_total = if has_bounds(x) /\ lb(x) >= 0 then x elseif has_bounds(x) /\ ub(x) <= 0 then -x else let { var 0..max(-lb(x),ub(x)): m ::is_defined_var; constraint int_abs(x,m) ::defines_var(m); } in m endif; /** @group builtins.arithmetic Return absolute value of \a x */ function float: abs(float: x); /** @group builtins.arithmetic Return absolute value of \a x */ function var float: abs(var float: x) :: promise_total = if has_bounds(x) then if lb(x) >= 0.0 then x elseif ub(x) <= 0.0 then -x else let { var 0.0..max(-lb(x),ub(x)): m ::is_defined_var; constraint float_abs(x,m) ::defines_var(m); } in m endif else let { var float: m ::is_defined_var; constraint m >= 0.0; constraint float_abs(x,m) ::defines_var(m); } in m endif; /** @group builtins.arithmetic Return \(\sqrt{\a x}\) */ function float: sqrt(float: x); /** @group builtins.arithmetic Return \(\sqrt{\a x}\) */ function var float: sqrt(var float: x) = let { constraint x >= 0.0; } in sqrt_t(x); function var float: sqrt_t(var float: x) ::promise_total = let { var float: r; var float: xx; constraint x < 0.0 -> xx = 1.0; constraint x < 0.0 \/ xx = x; constraint float_sqrt(xx,r); } in r; /** @group builtins.arithmetic Return \(\a x ^ {\a y}\) */ function int: pow(int: x, int: y); /** @group builtins.arithmetic Return \(\a x ^ {\a y}\) */ function var int: pow(var int: x, var int: y) = let { int: yy = if is_fixed(y) then fix(y) else -1 endif; } in if yy = 0 then 1 elseif yy = 1 then x else let { var int: r ::is_defined_var; constraint if is_fixed(y) then int_pow_fixed(x,fix(y),r) ::defines_var(r) else int_pow(x,y,r) ::defines_var(r) endif; } in r endif; /** @group builtins.arithmetic Return \(\a x ^ {\a y}\) */ function float: pow(float: x, float: y); /** @group builtins.arithmetic Return \(\a x ^ {\a y}\) */ function var float: pow(var float: x, var float: y) = let { float: yy = if is_fixed(y) then fix(y) else -1.0 endif } in if yy = 0.0 then 1.0 elseif yy = 1.0 then x else let { var float: r ::is_defined_var; constraint float_pow(x,y,r) ::defines_var(r); } in r endif; /*** @groupdef builtins.explog Exponential and logarithmic builtins These builtins implement exponential and logarithmic functions. */ /** @group builtins.explog Return \(e ^ {\a x}\) */ function float: exp(float: x); /** @group builtins.explog Return \(e ^ {\a x}\) */ function var float: exp(var float: x) ::promise_total = let { var float: r ::is_defined_var; constraint float_exp(x,r) ::defines_var(r); } in r; /** @group builtins.explog Return \(\ln \a x\) */ function float: ln(float: x); /** @group builtins.explog Return \(\ln \a x\) */ function var float: ln(var float: x) ::promise_total = let { var float: r ::is_defined_var; constraint float_ln(x,r) ::defines_var(r); } in r; /** @group builtins.explog Return \(\log_{10} \a x\) */ function float: log10(float: x); /** @group builtins.explog Return \(\log_{10} \a x\) */ function var float: log10(var float: x) ::promise_total = let { var float: r ::is_defined_var; constraint float_log10(x,r) ::defines_var(r); } in r; /** @group builtins.explog Return \(\log_{2} \a x\) */ function float: log2(float: x); /** @group builtins.explog Return \(\log_{2} \a x\) */ function var float: log2(var float: x) ::promise_total = let { var float: r ::is_defined_var; constraint float_log2(x,r) ::defines_var(r); } in r; /** @group builtins.explog Return \(\log_{\a x} \a y\) */ function float: log(float: x, float: y); /*** @groupdef builtins.trigonometric Trigonometric functions These builtins implement the standard trigonometric functions. */ /** @group builtins.trigonometric Return \(\sin \a x\) */ function float: sin(float: x); /** @group builtins.trigonometric Return \(\sin \a x\) */ function var float: sin(var float: x) ::promise_total = let { var -1.0..1.0: r ::is_defined_var; constraint float_sin(x,r) ::defines_var(r); } in r; /** @group builtins.trigonometric Return \(\cos \a x\) */ function float: cos(float: x); /** @group builtins.trigonometric Return \(\cos \a x\) */ function var float: cos(var float: x) ::promise_total = let { var -1.0..1.0: r ::is_defined_var; constraint float_cos(x,r) ::defines_var(r); } in r; /** @group builtins.trigonometric Return \(\tan \a x\) */ function float: tan(float: x); /** @group builtins.trigonometric Return \(\tan \a x\) */ function var float: tan(var float: x) ::promise_total = let { var float: r ::is_defined_var; constraint float_tan(x,r) ::defines_var(r); } in r; /** @group builtins.trigonometric Return \(\mbox{asin}\ \a x\) */ function float: asin(float: x); /** @group builtins.trigonometric Return \(\mbox{asin}\ \a x\) */ function var float: asin(var float: x) ::promise_total = let { var float: r ::is_defined_var; constraint float_asin(x,r) ::defines_var(r); } in r; /** @group builtins.trigonometric Return \(\mbox{acos}\ \a x\) */ function float: acos(float: x); /** @group builtins.trigonometric Return \(\mbox{acos}\ \a x\) */ function var float: acos(var float: x) ::promise_total = let { var float: r ::is_defined_var; constraint float_acos(x,r) ::defines_var(r); } in r; /** @group builtins.trigonometric Return \(\mbox{atan}\ \a x\) */ function float: atan(float: x); /** @group builtins.trigonometric Return \(\mbox{atan}\ \a x\) */ function var float: atan(var float: x) ::promise_total = let { var float: r ::is_defined_var; constraint float_atan(x,r) ::defines_var(r); } in r; /** @group builtins.trigonometric Return \(\sinh \a x\) */ function float: sinh(float: x); /** @group builtins.trigonometric Return \(\sinh \a x\) */ function var float: sinh(var float: x) ::promise_total = let { var float: r ::is_defined_var; constraint float_sinh(x,r) ::defines_var(r); } in r; /** @group builtins.trigonometric Return \(\cosh \a x\) */ function float: cosh(float: x); /** @group builtins.trigonometric Return \(\cosh \a x\) */ function var float: cosh(var float: x) ::promise_total = let { var float: r ::is_defined_var; constraint float_cosh(x,r) ::defines_var(r); } in r; /** @group builtins.trigonometric Return \(\tanh \a x\) */ function float: tanh(float: x); /** @group builtins.trigonometric Return \(\tanh \a x\) */ function var float: tanh(var float: x) ::promise_total = let { var float: r ::is_defined_var; constraint float_tanh(x,r) ::defines_var(r); } in r; /** @group builtins.trigonometric Return \(\mbox{asinh}\ \a x\) */ function float: asinh(float: x); /** @group builtins.trigonometric Return \(\mbox{asinh}\ \a x\) */ function var float: asinh(var float: x) ::promise_total = let { var float: r ::is_defined_var; constraint float_asinh(x,r) ::defines_var(r); } in r; /** @group builtins.trigonometric Return \(\mbox{acosh}\ \a x\) */ function float: acosh(float: x); /** @group builtins.trigonometric Return \(\mbox{acosh}\ \a x\) */ function var float: acosh(var float: x) ::promise_total = let { var float: r ::is_defined_var; constraint float_acosh(x,r) ::defines_var(r); } in r; /** @group builtins.trigonometric Return \(\mbox{atanh}\ \a x\) */ function float: atanh(float: x); /** @group builtins.trigonometric Return \(\mbox{atanh}\ \a x\) */ function var float: atanh(var float: x) ::promise_total = let { var float: r ::is_defined_var; constraint float_atanh(x,r) ::defines_var(r); } in r; /*** @groupdef builtins.logic Logical operations Logical operations are the standard operators of Boolean logic. */ /** @group builtins.logic Return truth value of \a x ∧ \a y */ function bool: '/\'( bool: x, bool: y); /** @group builtins.logic Return truth value of \a x ∧ \a y */ function var bool: '/\'(var bool: x, var bool: y); /** @group builtins.logic Return truth value of \a x ∨ \a y */ function bool: '\/'( bool: x, bool: y); /** @group builtins.logic Return truth value of \a x ∨ \a y */ function var bool: '\/'(var bool: x, var bool: y); /** @group builtins.logic Return truth value of \a x implies \a y */ function bool: '->'( bool: x, bool: y); /** @group builtins.logic Return truth value of \a x implies \a y */ function var bool: '->'(var bool: x, var bool: y); /** @group builtins.logic Return truth value of \a y implies \a x */ function bool: '<-'( bool: x, bool: y); /** @group builtins.logic Return truth value of \a y implies \a x */ function var bool: '<-'(var bool: x, var bool: y); /** @group builtins.logic Return truth value of \a x if-and-only-if \a y */ function bool: '<->'( bool: x, bool: y); /** @group builtins.logic Return truth value of \a x if-and-only-if \a y */ function var bool: '<->'(var bool: x, var bool: y); /** @group builtins.logic Return truth value of \a x xor \a y */ function bool: 'xor'( bool: x, bool: y); /** @group builtins.logic Return truth value of \a x xor \a y */ function var bool: 'xor'(var bool: x, var bool: y); /** @group builtins.logic Return truth value of the negation of \a x */ function bool: 'not'( bool: x); /** @group builtins.logic Return truth value of the negation of \a x */ function var bool: 'not'(var bool: x); /** @group builtins.logic Return truth value of \(\bigwedge_i \a x[i]\) */ function bool: forall(array[$T] of bool: x); /** @group builtins.logic Return truth value of \(\bigwedge_i \a x[i]\) */ function var bool: forall(array[$T] of var bool: x); /** @group builtins.logic Return truth value of \(\bigvee_i \a x[i]\) */ function bool: exists(array[$T] of bool: x); /** @group builtins.logic Return truth value of \(\bigvee_i \a x[i]\) */ function var bool: exists(array[$T] of var bool: x); /** @group builtins.logic Return truth value of \(\oplus_i \a x[i]\) */ function bool: xorall(array[$T] of bool: x); /** @group builtins.logic Return truth value of \(\oplus_i \a x[i]\) */ function var bool: xorall(array[$T] of var bool: x) = array_bool_xor(array1d(x)); /** @group builtins.logic Return truth value of \(\text{true}\oplus (\oplus_i \a x[i])\) */ function bool: iffall(array[$T] of bool: x); /** @group builtins.logic Return truth value of \(\text{true}\oplus (\oplus_i \a x[i])\) */ function var bool: iffall(array[$T] of var bool: x) = array_bool_xor(array1d(x)++[true]); /** @group builtins.logic Return truth value of \((\bigvee_i \a x[i]) \lor (\bigvee_j \lnot \a y[j])\) */ function var bool: clause(array[$T] of var bool: x, array[$T] of var bool: y); /** @group builtins.logic Return truth value of \((\bigvee_i \a x[i]) \lor (\bigvee_j \lnot \a y[j])\) */ function var bool: clause(array[$T] of bool: x, array[$T] of bool: y); /*** @groupdef builtins.set Set operations These functions implement the basic operations on sets. */ /** @group builtins.set Test if \a x is an element of the set \a y */ function bool: 'in'( int: x, set of int: y); /** @group builtins.set \a x is an element of the set \a y */ function var bool: 'in'(var int: x, var set of int: y); /** @group builtins.set Test if \a x is an element of the set \a y */ function bool: 'in'( float: x, set of float: y); /** @group builtins.set Test if \a x is an element of the set \a y */ function var bool: 'in'(var float: x, set of float: y); /** @group builtins.set Test if \a x is a subset of \a y */ function bool: 'subset'( set of $T: x, set of $T: y); /** @group builtins.set \a x is a subset of \a y */ function var bool: 'subset'(var set of int: x, var set of int: y); /** @group builtins.set Test if \a x is a superset of \a y */ function bool: 'superset'( set of $T: x, set of $T: y); /** @group builtins.set \a x is a superset of \a y */ function var bool: 'superset'(var set of int: x, var set of int: y); /** @group builtins.set Return the union of sets \a x and \a y */ function set of $T: 'union'( set of $T: x, set of $T: y); /** @group builtins.set Return the union of sets \a x and \a y */ function var set of $$T: 'union'(var set of $$T: x, var set of $$T: y); /** @group builtins.set Return the intersection of sets \a x and \a y */ function set of $T: 'intersect'( set of $T: x, set of $T: y); /** @group builtins.set Return the intersection of sets \a x and \a y */ function var set of $$T: 'intersect'(var set of $$T: x, var set of $$T: y); /** @group builtins.set Return the set difference of sets \(\a x \setminus \a y \) */ function set of $T: 'diff'( set of $T: x, set of $T: y); /** @group builtins.set Return the set difference of sets \(\a x \setminus \a y \) */ function var set of $$T: 'diff'(var set of $$T: x, var set of $$T: y); /** @group builtins.set Return the symmetric set difference of sets \a x and \a y */ function set of $T: 'symdiff'( set of $T: x, set of $T: y); /** @group builtins.set Return the symmetric set difference of sets \a x and \a y */ function var set of $$T: 'symdiff'(var set of $$T: x, var set of $$T: y); /** @group builtins.set Return the set \(\{\a a,\ldots,\a b\}\) */ function set of $$E: '..'($$E: a,$$E: b); /** @group builtins.set Return the set \(\{\a a,\ldots,\a b\}\) */ function set of float: '..'(float: a,float: b); function var set of int: '..'(var int: a, var int: b) ::promise_total = let { var set of min(lb(a),lb(b))..max(ub(a),ub(b)): s; constraint forall (i in ub(s)) (i in s <-> (a <= i /\ i <= b)); } in s; /** @group builtins.set Return the cardinality of the set \a x */ function int: card( set of $T: x); /** @group builtins.set Return the cardinality of the set \a x */ function var int: card(var set of int: x) ::promise_total = let { var 0..card(ub(x)): c; constraint set_card(x,c); } in c; /** @group builtins.set Return the union of the sets in array \a x */ function set of $U: array_union(array[$T] of set of $U: x); /** @group builtins.set Return the union of the sets in array \a x */ function var set of int: array_union(array[int] of var set of int: x) ::promise_total = if length(x)=0 then {} elseif length(x)=1 then x[min(index_set(x))] else let { int: l=min(index_set(x)); int: u=max(index_set(x)); array[l..u-1] of var set of ub_array(x): y; constraint y[l]=x[l] union x[l+1]; constraint forall (i in l+2..u) (y[i-1]=y[i-2] union x[i]); } in y[u-1] endif; /** @group builtins.set Return the intersection of the sets in array \a x */ function set of $U: array_intersect(array[$T] of set of $U: x); /** @group builtins.set Return the intersection of the sets in array \a x */ function var set of int: array_intersect(array[int] of var set of int: x) ::promise_total = if length(x)=0 then assert(false,"can't be!",-infinity..infinity) elseif length(x)=1 then x[min(index_set(x))] else let { int: l=min(index_set(x)); int: u=max(index_set(x)); array[l..u-1] of var set of ub_array(x): y; constraint y[l]=x[l] intersect x[l+1]; constraint forall (i in l+2..u) (y[i-1]=y[i-2] intersect x[i]); } in y[u-1] endif; /** @group builtins.set Return the minimum of the set \a s */ function var $$E: min(var set of $$E: s); /** @group builtins.set Return the maximum of the set \a s */ function var $$E: max(var set of $$E: s); /* Rewrite set membership on float variables to correct FlatZinc builtin */ predicate set_in(var float: x, set of float: S) = float_set_in(x, S); /** @group builtins.set Return a sorted list of the non-overlapping ranges in \a S */ function array[int] of int: set_to_ranges(set of int: S); /** @group builtins.set Return a sorted list of the non-overlapping ranges in \a S */ function array[int] of float: set_to_ranges(set of float: S); /** @group builtins.set Return a sorted list of the non-overlapping ranges in \a S */ function array[int] of bool: set_to_ranges(set of bool: S) = if S={false} then [false,false] elseif S={true} then [true,true] else [false,true] endif; /*** @groupdef builtins.ifthenelse Conditionals These functions implement conditional (if-then-else-endif) constraints. */ /** @group builtins.ifthenelse Conditional constraint \(\{\a c[i]\land\not\exists \a c[1..i-1]\ \rightarrow\ y=x[i] \}\) This constraint is generated by the compiler for if-then-else expressions. The last entry in the \a c array is always the constant true, corresponding to the else case. */ predicate if_then_else(array[int] of var bool: c, array[int] of int: x, var int: y) = fzn_if_then_else_int(c, x, y); /** @group builtins.ifthenelse Conditional constraint \(\{\a c[i]\land\not\exists \a c[1..i-1]\ \rightarrow\ y=x[i] \}\) This constraint is generated by the compiler for if-then-else expressions. The last entry in the \a c array is always the constant true, corresponding to the else case. */ predicate if_then_else(array[int] of var bool: c, array[int] of var int: x, var int: y) = fzn_if_then_else_var_int(c, x, y); /** @group builtins.ifthenelse Conditional constraint \(\{\a c[i]\land\not\exists \a c[1..i-1]\ \rightarrow\ y=x[i] \}\) This constraint is generated by the compiler for if-then-else expressions. The last entry in the \a c array is always the constant true, corresponding to the else case. */ predicate if_then_else(array[int] of var bool: c, array[int] of opt int: x, var opt int: y) = fzn_if_then_else_opt_int(c, x, y); /** @group builtins.ifthenelse Conditional constraint \(\{\a c[i]\land\not\exists \a c[1..i-1]\ \rightarrow\ y=x[i] \}\) This constraint is generated by the compiler for if-then-else expressions. The last entry in the \a c array is always the constant true, corresponding to the else case. */ predicate if_then_else(array[int] of var bool: c, array[int] of var opt int: x, var opt int: y) = fzn_if_then_else_var_opt_int(c, x, y); /** @group builtins.ifthenelse Conditional constraint \(\{\a c[i]\land\not\exists \a c[1..i-1]\ \rightarrow\ y=x[i] \}\) This constraint is generated by the compiler for if-then-else expressions. The last entry in the \a c array is always the constant true, corresponding to the else case. */ predicate if_then_else(array[int] of var bool: c, array[int] of bool: x, var bool: y) = fzn_if_then_else_bool(c, x, y); /** @group builtins.ifthenelse Conditional constraint \(\{\a c[i]\land\not\exists \a c[1..i-1]\ \rightarrow\ y=x[i] \}\) This constraint is generated by the compiler for if-then-else expressions. The last entry in the \a c array is always the constant true, corresponding to the else case. */ predicate if_then_else(array[int] of var bool: c, array[int] of var bool: x, var bool: y) = fzn_if_then_else_var_bool(c, x, y); /** @group builtins.ifthenelse Conditional constraint \(\{\a c[i]\land\not\exists \a c[1..i-1]\ \rightarrow\ y=x[i] \}\) This constraint is generated by the compiler for if-then-else expressions. The last entry in the \a c array is always the constant true, corresponding to the else case. */ predicate if_then_else(array[int] of var bool: c, array[int] of opt bool: x, var opt bool: y) = fzn_if_then_else_opt_bool(c, x, y); /** @group builtins.ifthenelse Conditional constraint \(\{\a c[i]\land\not\exists \a c[1..i-1]\ \rightarrow\ y=x[i] \}\) This constraint is generated by the compiler for if-then-else expressions. The last entry in the \a c array is always the constant true, corresponding to the else case. */ predicate if_then_else(array[int] of var bool: c, array[int] of var opt bool: x, var opt bool: y) = fzn_if_then_else_var_opt_bool(c, x, y); /** @group builtins.ifthenelse Conditional constraint \(\{\a c[i]\land\not\exists \a c[1..i-1]\ \rightarrow\ y=x[i] \}\) This constraint is generated by the compiler for if-then-else expressions. The last entry in the \a c array is always the constant true, corresponding to the else case. */ predicate if_then_else(array[int] of var bool: c, array[int] of float: x, var float: y) = fzn_if_then_else_float(c, x, y); /** @group builtins.ifthenelse Conditional constraint \(\{\a c[i]\land\not\exists \a c[1..i-1]\ \rightarrow\ y=x[i] \}\) This constraint is generated by the compiler for if-then-else expressions. The last entry in the \a c array is always the constant true, corresponding to the else case. */ predicate if_then_else(array[int] of var bool: c, array[int] of var float: x, var float: y) = fzn_if_then_else_var_float(c, x, y); /** @group builtins.ifthenelse Conditional constraint \(\{\a c[i]\land\not\exists \a c[1..i-1]\ \rightarrow\ y=x[i] \}\) This constraint is generated by the compiler for if-then-else expressions. The last entry in the \a c array is always the constant true, corresponding to the else case. */ predicate if_then_else(array[int] of var bool: c, array[int] of opt float: x, var opt float: y) = fzn_if_then_else_opt_float(c, x, y); /** @group builtins.ifthenelse Conditional constraint \(\{\a c[i]\land\not\exists \a c[1..i-1]\ \rightarrow\ y=x[i] \}\) This constraint is generated by the compiler for if-then-else expressions. The last entry in the \a c array is always the constant true, corresponding to the else case. */ predicate if_then_else(array[int] of var bool: c, array[int] of set of int: x, var set of int: y) = fzn_if_then_else_set(c, x, y); /** @group builtins.ifthenelse Conditional constraint \(\{\a c[i]\land\not\exists \a c[1..i-1]\ \rightarrow\ y=x[i] \}\) This constraint is generated by the compiler for if-then-else expressions. The last entry in the \a c array is always the constant true, corresponding to the else case. */ predicate if_then_else(array[int] of var bool: c, array[int] of var set of int: x, var set of int: y) = fzn_if_then_else_var_set(c, x, y); /** @group builtins.ifthenelse Conditional partiality constraint This constraint is generated by the compiler for if-then-else expressions with potentially undefined cases. The last entry in the \a c array is always the constant true, corresponding to the else case. The \a d[i] variable represents whether case \p i is defined. Constrains that if \b is defined, then the selected case must be defined, and if the selected case is undefined, then \a b must be undefined. */ predicate if_then_else_partiality(array[int] of var bool: c, array[int] of var bool: d, var bool: b) = fzn_if_then_else_partiality(c, d, b); /*** @groupdef builtins.array Array operations These functions implement the basic operations on arrays. */ /** @group builtins.array Return the concatenation of arrays \a x and \a y */ function array[int] of $T: '++'(array[int] of $T: x, array[int] of $T: y); /** @group builtins.array Return the concatenation of arrays \a x and \a y */ function array[int] of opt $T: '++'(array[int] of opt $T: x, array[int] of opt $T: y); /** @group builtins.array Return the concatenation of arrays \a x and \a y */ function array[int] of var $T: '++'(array[int] of var $T: x, array[int] of var $T: y); /** @group builtins.array Return the concatenation of arrays \a x and \a y */ function array[int] of var opt $T: '++'(array[int] of var opt $T: x, array[int] of var opt $T: y); /** @group builtins.array Return the length of array \a x Note that the length is defined as the number of elements in the array, regardless of its dimensionality. */ function int: length(array[$T] of var opt $U: x); /** @group builtins.array Return the array \a x in reverse order The resulting array has the same index set as \a x. */ function array[$$E] of $T: reverse(array[$$E] of $T: x) = let { int: l = max(index_set(x))+min(index_set(x)) } in array1d(index_set(x),[x[l-i] | i in index_set(x)]); /** @group builtins.array Return the array \a x in reverse order The resulting array has the same index set as \a x. */ function array[$$E] of opt $T: reverse(array[$$E] of opt $T: x) = let { int: l = max(index_set(x))+min(index_set(x)) } in array1d(index_set(x),[x[l-i] | i in index_set(x)]); /** @group builtins.array Return the array \a x in reverse order The resulting array has the same index set as \a x. */ function array[$$E] of var $T: reverse(array[$$E] of var $T: x) = let { int: l = max(index_set(x))+min(index_set(x)) } in array1d(index_set(x),[x[l-i] | i in index_set(x)]); /** @group builtins.array Return the array \a x in reverse order The resulting array has the same index set as \a x. */ function array[$$E] of var opt $T: reverse(array[$$E] of var opt $T: x) = let { int: l = max(index_set(x))+min(index_set(x)) } in array1d(index_set(x),[x[l-i] | i in index_set(x)]); /** @group builtins.array Test if \a x and \a y have the same index sets */ test index_sets_agree(array[$T] of var opt $U: x, array[$T] of var opt $W: y); /** @group builtins.array Return index set of one-dimensional array \a x */ function set of $$E: index_set(array[$$E] of var opt $U: x); /** @group builtins.array Return index set of first dimension of two-dimensional array \a x */ function set of $$E: index_set_1of2(array[$$E,int] of var opt $U: x); /** @group builtins.array Return index set of second dimension of two-dimensional array \a x */ function set of $$E: index_set_2of2(array[int,$$E] of var opt $U: x); /** @group builtins.array Return index set of first dimension of 3-dimensional array \a x */ function set of $$E: index_set_1of3(array[$$E,int,int] of var opt $U: x); /** @group builtins.array Return index set of second dimension of 3-dimensional array \a x */ function set of $$E: index_set_2of3(array[int,$$E,int] of var opt $U: x); /** @group builtins.array Return index set of third dimension of 3-dimensional array \a x */ function set of $$E: index_set_3of3(array[int,int,$$E] of var opt $U: x); /** @group builtins.array Return index set of first dimension of 4-dimensional array \a x */ function set of $$E: index_set_1of4(array[$$E,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of second dimension of 4-dimensional array \a x */ function set of $$E: index_set_2of4(array[int,$$E,int,int] of var opt $U: x); /** @group builtins.array Return index set of third dimension of 4-dimensional array \a x */ function set of $$E: index_set_3of4(array[int,int,$$E,int] of var opt $U: x); /** @group builtins.array Return index set of fourth dimension of 4-dimensional array \a x */ function set of $$E: index_set_4of4(array[int,int,int,$$E] of var opt $U: x); /** @group builtins.array Return index set of first dimension of 5-dimensional array \a x */ function set of $$E: index_set_1of5(array[$$E,int,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of second dimension of 5-dimensional array \a x */ function set of $$E: index_set_2of5(array[int,$$E,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of third dimension of 5-dimensional array \a x */ function set of $$E: index_set_3of5(array[int,int,$$E,int,int] of var opt $U: x); /** @group builtins.array Return index set of fourth dimension of 5-dimensional array \a x */ function set of $$E: index_set_4of5(array[int,int,int,$$E,int] of var opt $U: x); /** @group builtins.array Return index set of fifth dimension of 5-dimensional array \a x */ function set of $$E: index_set_5of5(array[int,int,int,int,$$E] of var opt $U: x); /** @group builtins.array Return index set of first dimension of 6-dimensional array \a x */ function set of $$E: index_set_1of6(array[$$E,int,int,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of second dimension of 6-dimensional array \a x */ function set of $$E: index_set_2of6(array[int,$$E,int,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of third dimension of 6-dimensional array \a x */ function set of $$E: index_set_3of6(array[int,int,$$E,int,int,int] of var opt $U: x); /** @group builtins.array Return index set of fourth dimension of 6-dimensional array \a x */ function set of $$E: index_set_4of6(array[int,int,int,$$E,int,int] of var opt $U: x); /** @group builtins.array Return index set of fifth dimension of 6-dimensional array \a x */ function set of $$E: index_set_5of6(array[int,int,int,int,$$E,int] of var opt $U: x); /** @group builtins.array Return index set of sixth dimension of 6-dimensional array \a x */ function set of $$E: index_set_6of6(array[int,int,int,int,int,$$E] of var opt $U: x); /** @group builtins.array Return array \a x coerced to index set 1..length(\a x). Coercions are perfomed by considering the array \a x in row-major order. */ function array[int] of $V: array1d(array[$U] of $V: x); /** @group builtins.array Return array \a x coerced to index set 1..length(\a x). Coercions are perfomed by considering the array \a x in row-major order. */ function array[int] of opt $V: array1d(array[$U] of opt $V: x); /** @group builtins.array Return array \a x coerced to index set 1..length(\a x). Coercions are perfomed by considering the array \a x in row-major order. */ function array[int] of var $V: array1d(array[$U] of var $V: x); /** @group builtins.array Return array \a x coerced to index set 1..length(\a x). Coercions are perfomed by considering the array \a x in row-major order. */ function array[int] of var opt $V: array1d(array[$U] of var opt $V: x); /** @group builtins.array Return array \a x coerced to one-dimensional array with index set \a S. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E] of $V: array1d(set of $$E: S, array[$U] of $V: x); /** @group builtins.array Return array \a x coerced to one-dimensional array with index set \a S. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E] of opt $V: array1d(set of $$E: S, array[$U] of opt $V: x); /** @group builtins.array Return array \a x coerced to one-dimensional array with index set \a S. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E] of var $V: array1d(set of $$E: S, array[$U] of var $V: x); /** @group builtins.array Return array \a x coerced to one-dimensional array with index set \a S. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E] of var opt $V: array1d(set of $$E: S, array[$U] of var opt $V: x); /** @group builtins.array Return array \a x coerced to two-dimensional array with index sets \a S1 and \a S2. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F] of $V: array2d(set of $$E: S1, set of $$F: S2, array[$U] of $V: x); /** @group builtins.array Return array \a x coerced to two-dimensional array with index sets \a S1 and \a S2. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F] of opt $V: array2d(set of $$E: S1, set of $$F: S2, array[$U] of opt $V: x); /** @group builtins.array Return array \a x coerced to two-dimensional array with index sets \a S1 and \a S2. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F] of var $V: array2d(set of $$E: S1, set of $$F: S2, array[$U] of var $V: x); /** @group builtins.array Return array \a x coerced to two-dimensional array with index sets \a S1 and \a S2. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F] of var opt $V: array2d(set of $$E: S1, set of $$F: S2, array[$U] of var opt $V: x); /** @group builtins.array Return array \a x coerced to three-dimensional array with index sets \a S1, \a S2 and \a S3. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F,$$G] of $V: array3d(set of $$E: S1, set of $$F: S2, set of $$G: S3, array[$U] of $V: x); /** @group builtins.array Return array \a x coerced to three-dimensional array with index sets \a S1, \a S2 and \a S3. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F,$$G] of opt $V: array3d(set of $$E: S1, set of $$F: S2, set of $$G: S3, array[$U] of opt $V: x); /** @group builtins.array Return array \a x coerced to three-dimensional array with index sets \a S1, \a S2 and \a S3. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F,$$G] of var $V: array3d(set of $$E: S1, set of $$F: S2, set of $$G: S3, array[$U] of var $V: x); /** @group builtins.array Return array \a x coerced to three-dimensional array with index sets \a S1, \a S2 and \a S3. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F,$$G] of var opt $V: array3d(set of $$E: S1, set of $$F: S2, set of $$G: S3, array[$U] of var opt $V: x); /** @group builtins.array Return array \a x coerced to 4-dimensional array with index sets \a S1, \a S2, \a S3 and \a S4. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F,$$G,$$H] of $V: array4d(set of $$E: S1, set of $$F: S2, set of $$G: S3, set of $$H: S4, array[$U] of $V: x); /** @group builtins.array Return array \a x coerced to 4-dimensional array with index sets \a S1, \a S2, \a S3 and \a S4. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F,$$G,$$H] of opt $V: array4d(set of $$E: S1, set of $$F: S2, set of $$G: S3, set of $$H: S4, array[$U] of opt $V: x); /** @group builtins.array Return array \a x coerced to 4-dimensional array with index sets \a S1, \a S2, \a S3 and \a S4. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F,$$G,$$H] of var $V: array4d(set of $$E: S1, set of $$F: S2, set of $$G: S3, set of $$H: S4, array[$U] of var $V: x); /** @group builtins.array Return array \a x coerced to 4-dimensional array with index sets \a S1, \a S2, \a S3 and \a S4. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F,$$G,$$H] of var opt $V: array4d(set of $$E: S1, set of $$F: S2, set of $$G: S3, set of $$H: S4, array[$U] of var opt $V: x); /** @group builtins.array Return array \a x coerced to 5-dimensional array with index sets \a S1, \a S2, \a S3, \a S4 and \a S5. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F,$$G,$$H,$$I] of $V: array5d(set of $$E: S1, set of $$F: S2, set of $$G: S3, set of $$H: S4, set of $$I: S5, array[$U] of $V: x); /** @group builtins.array Return array \a x coerced to 5-dimensional array with index sets \a S1, \a S2, \a S3, \a S4 and \a S5. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F,$$G,$$H,$$I] of opt $V: array5d(set of $$E: S1, set of $$F: S2, set of $$G: S3, set of $$H: S4, set of $$I: S5, array[$U] of opt $V: x); /** @group builtins.array Return array \a x coerced to 5-dimensional array with index sets \a S1, \a S2, \a S3, \a S4 and \a S5. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F,$$G,$$H,$$I] of var $V: array5d(set of $$E: S1, set of $$F: S2, set of $$G: S3, set of $$H: S4, set of $$I: S5, array[$U] of var $V: x); /** @group builtins.array Return array \a x coerced to 5-dimensional array with index sets \a S1, \a S2, \a S3, \a S4 and \a S5. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F,$$G,$$H,$$I] of var opt $V: array5d(set of $$E: S1, set of $$F: S2, set of $$G: S3, set of $$H: S4, set of $$I: S5, array[$U] of var opt $V: x); /** @group builtins.array Return array \a x coerced to 6-dimensional array with index sets \a S1, \a S2, \a S3, \a S4, \a S5 and \a S6. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F,$$G,$$H,$$I,$$J] of $V: array6d(set of $$E: S1, set of $$F: S2, set of $$G: S3, set of $$H: S4, set of $$I: S5, set of $$J: S6, array[$U] of $V: x); /** @group builtins.array Return array \a x coerced to 6-dimensional array with index sets \a S1, \a S2, \a S3, \a S4, \a S5 and \a S6. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F,$$G,$$H,$$I,$$J] of opt $V: array6d(set of $$E: S1, set of $$F: S2, set of $$G: S3, set of $$H: S4, set of $$I: S5, set of $$J: S6, array[$U] of opt $V: x); /** @group builtins.array Return array \a x coerced to 6-dimensional array with index sets \a S1, \a S2, \a S3, \a S4, \a S5 and \a S6. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F,$$G,$$H,$$I,$$J] of var $V: array6d(set of $$E: S1, set of $$F: S2, set of $$G: S3, set of $$H: S4, set of $$I: S5, set of $$J: S6, array[$U] of var $V: x); /** @group builtins.array Return array \a x coerced to 6-dimensional array with index sets \a S1, \a S2, \a S3, \a S4, \a S5 and \a S6. Coercions are perfomed by considering the array \a x in row-major order. */ function array[$$E,$$F,$$G,$$H,$$I,$$J] of var opt $V: array6d(set of $$E: S1, set of $$F: S2, set of $$G: S3, set of $$H: S4, set of $$I: S5, set of $$J: S6, array[$U] of var opt $V: x); /** @group builtins.array Return array \a y coerced to array with same number of dimensions and same index sets as array \a x. Coercions are perfomed by considering the array \a y in row-major order. */ function array[$T] of $V: arrayXd(array[$T] of var opt $X: x, array[$U] of $V: y); /** @group builtins.array Return array \a y coerced to array with same number of dimensions and same index sets as array \a x. Coercions are perfomed by considering the array \a y in row-major order. */ function array[$T] of opt $V: arrayXd(array[$T] of var opt $X: x, array[$U] of opt $V: y); /** @group builtins.array Return array \a y coerced to array with same number of dimensions and same index sets as array \a x. Coercions are perfomed by considering the array \a y in row-major order. */ function array[$T] of var $V: arrayXd(array[$T] of var opt $X: x, array[$U] of var $V: y); /** @group builtins.array Return array \a y coerced to array with same number of dimensions and same index sets as array \a x. Coercions are perfomed by considering the array \a y in row-major order. */ function array[$T] of var opt $V: arrayXd(array[$T] of var opt $X: x, array[$U] of var opt $V: y); /** @group builtins.array Return row \a r of array \a x */ function array[$$E] of $T: row(array[int, $$E] of $T: x, int: r) = x[r,..]; /** @group builtins.array Return row \a r of array \a x */ function array[$$E] of opt $T: row(array[int, $$E] of opt $T: x, int: r) = x[r,..]; /** @group builtins.array Return row \a r of array \a x */ function array[$$E] of var $T: row(array[int, $$E] of var $T: x, int: r) = x[r,..]; /** @group builtins.array Return row \a r of array \a x */ function array[$$E] of var opt $T: row(array[int, $$E] of var opt $T: x, int: r) = x[r,..]; /** @group builtins.array Return column \a c of array \a x */ function array[$$E] of $T: col(array[$$E,int] of $T: x, int: c) = x[..,c]; /** @group builtins.array Return column \a c of array \a x */ function array[$$E] of opt $T: col(array[$$E,int] of opt $T: x, int: c) = x[..,c]; /** @group builtins.array Return column \a c of array \a x */ function array[$$E] of var $T: col(array[$$E,int] of var $T: x, int: c) = x[..,c]; /** @group builtins.array Return column \a c of array \a x */ function array[$$E] of var opt $T: col(array[$$E,int] of var opt $T: x, int: c) = x[..,c]; /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 1d array with index set \a dims1 */ function array[int] of $T: slice_1d(array[$E] of $T: x, array[int] of set of int: s, set of int: dims1); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 2d array with index sets \a dims1 and \a dims2 */ function array[int,int] of $T: slice_2d(array[$E] of $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 3d array with index sets \a dims1, \a dims2 and \a dims3 */ function array[int,int,int] of $T: slice_3d(array[$E] of $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2, set of int: dims3); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 3d array with index sets \a dims1, \a dims2, \a dims3, \a dims4 */ function array[int,int,int] of $T: slice_4d(array[$E] of $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2, set of int: dims3, set of int: dims4); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 3d array with index sets \a dims1, \a dims2, \a dims3, \a dims4, \a dims5 */ function array[int,int,int] of $T: slice_5d(array[$E] of $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2, set of int: dims3, set of int: dims4, set of int: dims5); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 3d array with index sets \a dims1, \a dims2, \a dims3, \a dims4, \a dims5, \a dims6 */ function array[int,int,int] of $T: slice_6d(array[$E] of $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2, set of int: dims3, set of int: dims4, set of int: dims5, set of int: dims6); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 1d array with index set \a dims1 */ function array[int] of opt $T: slice_1d(array[$E] of opt $T: x, array[int] of set of int: s, set of int: dims1); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 2d array with index sets \a dims1 and \a dims2 */ function array[int,int] of opt $T: slice_2d(array[$E] of opt $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 3d array with index sets \a dims1, \a dims2 and \a dims3 */ function array[int,int,int] of opt $T: slice_3d(array[$E] of opt $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2, set of int: dims3); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 3d array with index sets \a dims1, \a dims2, \a dims3, \a dims4 */ function array[int,int,int] of opt $T: slice_4d(array[$E] of opt $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2, set of int: dims3, set of int: dims4); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 3d array with index sets \a dims1, \a dims2, \a dims3, \a dims4, \a dims5 */ function array[int,int,int] of opt $T: slice_5d(array[$E] of opt $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2, set of int: dims3, set of int: dims4, set of int: dims5); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 3d array with index sets \a dims1, \a dims2, \a dims3, \a dims4, \a dims5, \a dims6 */ function array[int,int,int] of opt $T: slice_6d(array[$E] of opt $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2, set of int: dims3, set of int: dims4, set of int: dims5, set of int: dims6); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 1d array with index set \a dims1 */ function array[int] of var $T: slice_1d(array[$E] of var $T: x, array[int] of set of int: s, set of int: dims1); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 2d array with index sets \a dims1 and \a dims2 */ function array[int,int] of var $T: slice_2d(array[$E] of var $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 3d array with index sets \a dims1, \a dims2 and \a dims3 */ function array[int,int,int] of var $T: slice_3d(array[$E] of var $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2, set of int: dims3); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 3d array with index sets \a dims1, \a dims2, \a dims3, \a dims4 */ function array[int,int,int] of var $T: slice_4d(array[$E] of var $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2, set of int: dims3, set of int: dims4); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 3d array with index sets \a dims1, \a dims2, \a dims3, \a dims4, \a dims5 */ function array[int,int,int] of var $T: slice_5d(array[$E] of var $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2, set of int: dims3, set of int: dims4, set of int: dims5); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 3d array with index sets \a dims1, \a dims2, \a dims3, \a dims4, \a dims5, \a dims6 */ function array[int,int,int] of var $T: slice_6d(array[$E] of var $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2, set of int: dims3, set of int: dims4, set of int: dims5, set of int: dims6); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 1d array with index set \a dims1 */ function array[int] of var opt $T: slice_1d(array[$E] of var opt $T: x, array[int] of set of int: s, set of int: dims1); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 2d array with index sets \a dims1 and \a dims2 */ function array[int,int] of var opt $T: slice_2d(array[$E] of var opt $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 3d array with index sets \a dims1, \a dims2 and \a dims3 */ function array[int,int,int] of var opt $T: slice_3d(array[$E] of var opt $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2, set of int: dims3); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 3d array with index sets \a dims1, \a dims2, \a dims3, \a dims4 */ function array[int,int,int] of var opt $T: slice_4d(array[$E] of var opt $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2, set of int: dims3, set of int: dims4); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 3d array with index sets \a dims1, \a dims2, \a dims3, \a dims4, \a dims5 */ function array[int,int,int] of var opt $T: slice_5d(array[$E] of var opt $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2, set of int: dims3, set of int: dims4, set of int: dims5); /** @group builtins.array Return slice of array \a x specified by sets \a s, coerced to new 3d array with index sets \a dims1, \a dims2, \a dims3, \a dims4, \a dims5, \a dims6 */ function array[int,int,int] of var opt $T: slice_6d(array[$E] of var opt $T: x, array[int] of set of int: s, set of int: dims1, set of int: dims2, set of int: dims3, set of int: dims4, set of int: dims5, set of int: dims6); /** @group builtins.array Test if \a i is in the index set of \a x */ test has_index(int: i, array[int] of var opt $T: x) = i in index_set(x); /** @group builtins.array Test if \a e is an element of array \a x */ test has_element($T: e, array[int] of $T: x) = exists (i in index_set(x)) (x[i]=e); /** @group builtins.array Test if \a e is an element of array \a x */ test has_element($T: e, array[int] of opt $T: x) = exists (i in index_set(x)) (x[i]=e); /** @group builtins.array Test if \a e is an element of array \a x */ predicate has_element($T: e, array[$$E] of var opt $T: x) = exists (i in index_set(x)) (x[i]=e); /*** @groupdef builtins.sort Array sorting operations */ /** @group builtins.sort Return array \a x sorted by the values in \a y in non-decreasing order The sort is stable, i.e. if \a y[\p i] = \a y[\p j] with \p i < \p j, then \a x[\p i] will appear in the output before \a x[\p j]. */ function array[$$E] of var opt $T: sort_by(array[$$E] of var opt $T: x, array[$$E] of int: y); /** @group builtins.sort Return array \a x sorted by the values in \a y in non-decreasing order The sort is stable, i.e. if \a y[\p i] = \a y[\p j] with \p i < \p j, then \a x[\p i] will appear in the output before \a x[\p j]. */ function array[$$E] of var $T: sort_by(array[$$E] of var $T: x, array[$$E] of int: y); /** @group builtins.sort Return array \a x sorted by the values in \a y in non-decreasing order The sort is stable, i.e. if \a y[\p i] = \a y[\p j] with \p i < \p j, then \a x[\p i] will appear in the output before \a x[\p j]. */ function array[$$E] of $T: sort_by(array[$$E] of $T: x, array[$$E] of int: y); /** @group builtins.sort Return array \a x sorted by the values in \a y in non-decreasing order The sort is stable, i.e. if \a y[\p i] = \a y[\p j] with \p i < \p j, then \a x[\p i] will appear in the output before \a x[\p j]. */ function array[$$E] of var opt $T: sort_by(array[$$E] of var opt $T: x, array[$$E] of float: y); /** @group builtins.sort Return array \a x sorted by the values in \a y in non-decreasing order The sort is stable, i.e. if \a y[\p i] = \a y[\p j] with \p i < \p j, then \a x[\p i] will appear in the output before \a x[\p j]. */ function array[$$E] of var $T: sort_by(array[$$E] of var $T: x, array[$$E] of float: y); /** @group builtins.sort Return array \a x sorted by the values in \a y in non-decreasing order The sort is stable, i.e. if \a y[\p i] = \a y[\p j] with \p i < \p j, then \a x[\p i] will appear in the output before \a x[\p j]. */ function array[$$E] of $T: sort_by(array[$$E] of $T: x, array[$$E] of float: y); /** @group builtins.sort Return values from array \a x sorted in non-decreasing order */ function array[$$E] of int: sort(array[$$E] of int: x); /** @group builtins.sort Return values from array \a x sorted in non-decreasing order */ function array[$$E] of float: sort(array[$$E] of float: x); /** @group builtins.sort Return values from array \a x sorted in non-decreasing order */ function array[$$E] of bool: sort(array[$$E] of bool: x); /** @group builtins.sort Returns the permutation \a p which causes \a x to be in sorted order hence \a x[\a p[\p i]] <= \a x[\a p[\p i+1]]. The permutation is the stable sort hence \a x[\a p[\p i]] = \a x[\a p[\p i+1]] \(\rightarrow\) \a p[\p i] < \a p[\p i+1]. */ function array[int] of $$E: arg_sort(array[$$E] of int:x) = sort_by([i | i in index_set(x)], x); /** @group builtins.sort Returns the permutation \a p which causes \a x to be in sorted order hence \a x[\a p[\p i]] <= \a x[\a p[\p i+1]]. The permutation is the stable sort hence \a x[\a p[\p i]] = \a x[\a p[\p i+1]] \(\rightarrow\) \a p[\p i] < \a p[\p i+1]. */ function array[int] of $$E: arg_sort(array[$$E] of float:x) = sort_by([i | i in index_set(x)], x); /*** @groupdef builtins.coercion Coercions These functions implement coercions, or channeling, between different types. */ /** @group builtins.coercion Return \( \lceil{ \a x} \rceil \) */ function int: ceil(float: x); /** @group builtins.coercion Return \( \lfloor{ \a x} \rfloor \) */ function int: floor(float: x); /** @group builtins.coercion Return \a x rounded to nearest integer */ function int: round(float: x); /** @group builtins.coercion Return Boolean \a b coerced to an integer */ function int: bool2int(bool: b); /** @group builtins.coercion Return Boolean \a b coerced to a float */ function float: bool2float(bool: b) = if b then 1.0 else 0.0 endif; /** @group builtins.coercion Return array of Booleans \a x coerced to an array of floats */ function array[$T] of float: bool2float(array[$T] of bool: x) ::promise_total = let { array[int] of bool: xx = array1d(x) } in arrayXd(x,[bool2float(xx[i]) | i in index_set(xx)]); /** @group builtins.coercion Return array of Booleans \a x coerced to an array of floats */ function array[$T] of var float: bool2float(array[$T] of var bool: x) ::promise_total = let { array[int] of var bool: xx = array1d(x) } in arrayXd(x,[bool2float(xx[i]) | i in index_set(xx)]); /** @group builtins.coercion Return Boolean \a b coerced to an integer */ function var int: bool2int(var bool: b); /** @group builtins.coercion Return array of Booleans \a b coerced to an array of integers */ function array[$T] of var int: bool2int(array[$T] of var bool: b); /** @group builtins.coercion Return Boolean \a b coerced to a float */ function var float: bool2float(var bool: b) = int2float(bool2int(b)); /** @group builtins.coercion Return integer \a x coerced to a float */ function float: int2float(int: x); /** @group builtins.coercion Return integer \a x coerced to a float */ function var float: int2float(var int: x) ::promise_total; function set of int: bool2int(set of bool: b) = if b={false,true} then {0,1} elseif b={false} then {0} elseif b={true} then {1} else {} endif; /** @group builtins.coercion Return array of Booleans \a x coerced to an array of integers */ function array[$T] of int: bool2int(array[$T] of bool: x) ::promise_total = let { array[int] of bool: xx = array1d(x) } in arrayXd(x,[bool2int(xx[i]) | i in index_set(xx)]); /** @group builtins.coercion Return array of sets of Booleans \a x coerced to an array of sets of integers */ function array[$T] of set of int: bool2int(array[$T] of set of bool: x) ::promise_total = let { array[int] of set of bool: xx = array1d(x) } in arrayXd(x,[bool2int(xx[i]) | i in index_set(xx)]); /** @group builtins.coercion Return array of Booleans \a x coerced to an array of integers */ function array[$T] of var int: bool2int(array[$T] of var bool: x) ::promise_total = let { array[int] of var bool: xx = array1d(x) } in arrayXd(x,[bool2int(xx[i]) | i in index_set(xx)]); /** @group builtins.coercion Return array of Booleans \a x coerced to an array of integers */ function array[$T] of var opt int: bool2int(array[$T] of var opt bool: x) ::promise_total = let { array[int] of var opt bool: xx = array1d(x) } in arrayXd(x,[bool2int(xx[i]) | i in index_set(xx)]); /** @group builtins.coercion Return array of Booleans \a x coerced to an array of floats */ function array[$T] of var opt float: bool2float(array[$T] of var opt bool: x) ::promise_total = let { array[int] of var opt bool: xx = array1d(x) } in arrayXd(x,[bool2float(xx[i]) | i in index_set(xx)]); /** @group builtins.coercion Return array of integers \a x coerced to an array of floats */ function array[$T] of float: int2float(array[$T] of int: x) ::promise_total = let { array[int] of int: xx = array1d(x) } in arrayXd(x,[int2float(xx[i]) | i in index_set(xx)]); /** @group builtins.coercion Return array of integers \a x coerced to an array of floats */ function array[$T] of var float: int2float(array[$T] of var int: x) ::promise_total = let { array[int] of var int: xx = array1d(x) } in arrayXd(x,[int2float(xx[i]) | i in index_set(xx)]); /** @group builtins.coercion Return array of optional integers \a x coerced to an array of optional floats */ function array[$T] of var opt float: int2float(array[$T] of var opt int: x) ::promise_total = let { array[int] of var opt int: xx = array1d(x) } in arrayXd(x,[int2float(xx[i]) | i in index_set(xx)]); % Only supported for set of int: % function array[int] of $T: set2array(set of $T); /** @group builtins.coercion Return a set of integers \a x coerced to an array of integers */ function array[int] of $$E: set2array(set of $$E: x); /*** @groupdef builtins.string String operations These functions implement operations on strings. */ /** @group builtins.string Convert \a x into a string */ function string: show(var opt set of $T: x); /** @group builtins.string Convert \a x into a string */ function string: show(var opt $T: x); /** @group builtins.string Convert \a x into a string */ function string: show(array[$U] of var opt $T: x); function string: showDzn(var opt set of $T: x); function string: showDzn(var opt $T: x); function string: showDzn(array[$U] of var opt $T: x); function string: showDznId(string: x); /** @group builtins.string Formatted to-string conversion for integers Converts the integer \a x into a string right justified by the number of characters given by \a w, or left justified if \a w is negative. */ function string: show_int(int: w, var int: x); /** @group builtins.string Formatted to-string conversion for floats. Converts the float \a x into a string right justified by the number of characters given by \a w, or left justified if \a w is negative. The number of digits to appear after the decimal point is given by \a p. It is a run-time error for \a p to be negative. */ function string: show_float(int: w, int: p, var float: x); /** @group builtins.string Convert two-dimensional array \a x into a string */ function string: show2d(array[int,int] of var opt $T: x) = let { int: rows=card(index_set_1of2(x)); int: cols=card(index_set_2of2(x)); array[int] of string: s = [show(x[i,j]) | i in index_set_1of2(x), j in index_set_2of2(x)]; int: max_length = max([string_length(s[i]) | i in index_set(s)]) } in "[| "++ concat([format_justify_string(max_length,s[(i-1)*cols+j])++ if j min(e) } in x-1; /** @group builtins.enum Convert \a x to enum type \a X */ function $$E: to_enum(set of $$E: X, int: x); /** @group builtins.enum Convert \a x to enum type \a X */ function var $$E: to_enum(set of $$E: X, var int: x) = let { constraint x in X } in x; /** @group builtins.enum Convert \a x to enum type \a X */ function array[$U] of $$E: to_enum(set of $$E: X, array[$U] of int: x) = let { array[int] of int: xx = array1d(x) } in arrayXd(x, [ to_enum(X,xx[i]) | i in index_set(xx)]); /** @group builtins.enum Convert \a x to enum type \a X */ function array[$U] of var $$E: to_enum(set of $$E: X, array[$U] of var int: x) = let { array[int] of var int: xx = array1d(x) } in arrayXd(x, [ to_enum(X,xx[i]) | i in index_set(xx)]); /** @group builtins.enum Convert \a x to enum type \a X */ function set of $$E: to_enum(set of $$E: X, set of int: x) = { to_enum(X,i) | i in x }; %/** @group builtins.enum Convert \a x to enum type \a X */ function var set of $$E: to_enum(set of $$E: X, var set of int: x) = let { var set of X: y; constraint x subset X; constraint forall (i in X) (i in x <-> i in y); } in y; %-----------------------------------------------------------------------------% % % Internal compiler functions % % These functions are used internally by the compiler. % % domain constraints predicate var_dom(var int:x, set of int: s) = if has_bounds(x) /\ dom(x) subset s then true else x in s endif; predicate var_dom(var set of int: x, set of int: s) = if has_ub_set(x) /\ ub(x) subset s then true else set_subset(x,s) endif; predicate var_dom(var float:x, float: l, float: u) = if has_bounds(x) /\ lb(x) >= l /\ ub(x) <= u then true else x >= l /\ x <= u endif; predicate var_dom(var float:x, set of float: d) = x in d; test var_dom(float:x, float: l, float: u) = x >= l /\ x <= u; test var_dom(float:x, set of float: d) = x in d; predicate var_dom(array[$T] of var set of int: x, set of int: d) = let { array[int] of var set of int: xx = array1d(x) } in forall (i in index_set(xx)) (var_dom(xx[i],d)); predicate var_dom(array[$T] of var int: x, set of int: d) = let { array[int] of var int: xx = array1d(x) } in forall (i in index_set(xx)) (var_dom(xx[i],d)); predicate var_dom(array[$T] of var float: x, float: l, float: u) = let { array[int] of var float: xx = array1d(x) } in forall (i in index_set(xx)) (var_dom(xx[i],l,u)); predicate var_dom(array[$T] of var float: x, set of float: d) = let { array[int] of var float: xx = array1d(x) } in forall (i in index_set(xx)) (var_dom(xx[i],d)); test var_dom(array[$T] of set of int: x, set of int: d) = let { array[int] of set of int: xx = array1d(x) } in forall (i in index_set(xx)) (xx[i] subset d); test var_dom(array[$T] of int: x, set of int: d) = let { array[int] of int: xx = array1d(x) } in forall (i in index_set(xx)) (xx[i] in d); test var_dom(array[$T] of float: x, float: l, float: u) = let { array[int] of float: xx = array1d(x) } in forall (i in index_set(xx)) (var_dom(xx[i],l,u)); test var_dom(array[$T] of float: x, set of float: d) = let { array[int] of float: xx = array1d(x) } in forall (i in index_set(xx)) (var_dom(xx[i],d)); function var set of int: array2set(array[int] of var int: x) ::promise_total = let { var set of int: y = array_union([ let { var set of dom(x[i]): s; constraint x[i] in s /\ card(s)=1; } in s | i in index_set(x)]); } in y; function set of $$T: array2set(array[int] of $$T: x) = { x[i] | i in index_set(x) }; predicate array_var_int_element(var int: x, array[int] of int: y, var int: z) = array_int_element(x,y,z); predicate array_var_bool_element(var int: x, array[int] of bool: y, var bool: z) = array_bool_element(x,y,z); predicate array_var_float_element(var int: x, array[int] of float: y, var float: z) = array_float_element(x,y,z); predicate array_var_set_element(var int: x, array[int] of set of int: y, var set of int: z) = array_set_element(x,y,z); predicate bool_xor_reif(var bool: a, var bool: b, var bool: c) = bool_xor(a,b,c); predicate xorall_reif(array[int] of var bool: b, var bool: c) = let { var bool: nc ::is_defined_var; constraint xorall([nc]++b) ::defines_var(nc); } in c = not nc; function var int: lin_exp(array[int] of int, array[int] of var int, int); function var float: lin_exp(array[int] of float, array[int] of var float, float); test mzn_in_root_context(var $T); test mzn_in_redundant_constraint(); %-----------------------------------------------------------------------------% % % Element constraint implementations % % MiniZinc compiles element constraints using a series of intermediate % functions that test whether the constraint is total and perform array slicing % for multi-dimensional element constraints. % %%%%%%%%%%%%%%%%%%% % Element on ints function var int: element_t(var int: idx, array[int] of var int: x) :: promise_total = let { var dom_bounds_array(x): r ::is_defined_var; constraint idx in index_set(x); constraint array_var_int_element_nonshifted(idx,x,r) ::defines_var(r); } in r; function var int: element_mt(var int: idx, array[int] of var int: x) :: promise_total = let { var lb_array(x)..ub_array(x): r ::is_defined_var; var min(index_set(x))..max(index_set(x)): idx2; constraint idx in index_set(x) -> idx2=idx; constraint idx in index_set(x) \/ idx2=min(index_set(x)); constraint array_var_int_element_nonshifted(idx2,x,r) ::defines_var(r); } in r; function var int: element(var int: idx, array[int] of var int: x) = if mzn_in_root_context(idx) then let { constraint idx in index_set(x) } in element_t(idx,x) elseif (has_bounds(idx) /\ lb(idx) >= min(index_set(x)) /\ ub(idx) <= max(index_set(x))) then element_t(idx,x) else let { constraint idx in index_set(x) } in element_mt(idx,x) endif; function var int: element(var int: idx1, var int: idx2, array[int,int] of var int: x) = let { int: dim = card(index_set_2of2(x)); int: min_flat = min(index_set_1of2(x))*dim+min(index_set_2of2(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of2(x); constraint idx2 in index_set_2of2(x); } in element_t( (idx1*dim+idx2-min_flat)::domain, array1d(x)) elseif ((has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of2(x)) /\ ub(idx1) <= max(index_set_1of2(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of2(x)) /\ ub(idx2) <= max(index_set_2of2(x)))) then element_t( (idx1*dim+idx2-min_flat)::domain, array1d(x)) else let { constraint idx1 in index_set_1of2(x); constraint idx2 in index_set_2of2(x); } in element_mt( (idx1*dim+idx2-min_flat)::domain, array1d(x)) endif; function var int: element(var int: idx1, var int: idx2, var int: idx3, array[int,int,int] of var int: x) = let { int: dim2 = card(index_set_2of3(x)); int: dim3 = card(index_set_3of3(x)); int: min = min(index_set_1of3(x))*dim2*dim3+ min(index_set_2of3(x))*dim3+ min(index_set_3of3(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of3(x); constraint idx2 in index_set_2of3(x); constraint idx3 in index_set_3of3(x); } in element_t( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) elseif ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of3(x)) /\ ub(idx1) <= max(index_set_1of3(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of3(x)) /\ ub(idx2) <= max(index_set_2of3(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of3(x)) /\ ub(idx3) <= max(index_set_3of3(x)))) then element_t( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of3(x); constraint idx2 in index_set_2of3(x); constraint idx3 in index_set_3of3(x); } in element_mt( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) endif; function var int: element(var int: idx1, var int: idx2, var int: idx3, var int: idx4, array[int,int,int,int] of var int: x) = let { int: dim2 = card(index_set_2of4(x)); int: dim3 = card(index_set_3of4(x)); int: dim4 = card(index_set_4of4(x)); int: min = min(index_set_1of4(x))*dim2*dim3*dim4+ min(index_set_2of4(x))*dim3*dim4+ min(index_set_3of4(x))*dim4+ min(index_set_4of4(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of4(x); constraint idx2 in index_set_2of4(x); constraint idx3 in index_set_3of4(x); constraint idx4 in index_set_4of4(x); } in element_t( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) elseif ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of4(x)) /\ ub(idx1) <= max(index_set_1of4(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of4(x)) /\ ub(idx2) <= max(index_set_2of4(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of4(x)) /\ ub(idx3) <= max(index_set_3of4(x))) /\ (has_bounds(idx4) /\ lb(idx4) >= min(index_set_4of4(x)) /\ ub(idx4) <= max(index_set_4of4(x))) ) then element_t( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of4(x); constraint idx2 in index_set_2of4(x); constraint idx3 in index_set_3of4(x); constraint idx4 in index_set_4of4(x); } in element_mt( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) endif; function var int: element(var int: idx1, var int: idx2, var int: idx3, var int: idx4, var int: idx5, array[int,int,int,int,int] of var int: x) = let { int: dim2 = card(index_set_2of5(x)); int: dim3 = card(index_set_3of5(x)); int: dim4 = card(index_set_4of5(x)); int: dim5 = card(index_set_5of5(x)); int: min = min(index_set_1of5(x))*dim2*dim3*dim4*dim5+ min(index_set_2of5(x))*dim3*dim4*dim5+ min(index_set_3of5(x))*dim4*dim5+ min(index_set_4of5(x))*dim5+ min(index_set_5of5(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of5(x); constraint idx2 in index_set_2of5(x); constraint idx3 in index_set_3of5(x); constraint idx4 in index_set_4of5(x); constraint idx5 in index_set_5of5(x); } in element_t( (idx1*(dim2*dim3*dim4*dim5)+idx2*(dim3*dim4*dim5)+idx3*(dim4*dim5)+idx4*dim5+idx5-min)::domain, array1d(x)) elseif ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of5(x)) /\ ub(idx1) <= max(index_set_1of5(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of5(x)) /\ ub(idx2) <= max(index_set_2of5(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of5(x)) /\ ub(idx3) <= max(index_set_3of5(x))) /\ (has_bounds(idx4) /\ lb(idx4) >= min(index_set_4of5(x)) /\ ub(idx4) <= max(index_set_4of5(x))) /\ (has_bounds(idx5) /\ lb(idx5) >= min(index_set_5of5(x)) /\ ub(idx5) <= max(index_set_5of5(x))) ) then element_t( (idx1*(dim2*dim3*dim4*dim5)+idx2*(dim3*dim4*dim5)+idx3*(dim4*dim5)+idx4*dim5+idx5-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of5(x); constraint idx2 in index_set_2of5(x); constraint idx3 in index_set_3of5(x); constraint idx4 in index_set_4of5(x); constraint idx5 in index_set_5of5(x); } in element_mt( (idx1*(dim2*dim3*dim4*dim5)+idx2*(dim3*dim4*dim5)+idx3*(dim4*dim5)+idx4*dim5+idx5-min)::domain, array1d(x)) endif; function var int: element(var int: idx1, var int: idx2, var int: idx3, var int: idx4, var int: idx5, var int: idx6, array[int,int,int,int,int,int] of var int: x) = let { int: dim2 = card(index_set_2of6(x)); int: dim3 = card(index_set_3of6(x)); int: dim4 = card(index_set_4of6(x)); int: dim5 = card(index_set_5of6(x)); int: dim6 = card(index_set_6of6(x)); int: min = min(index_set_1of6(x))*dim2*dim3*dim4*dim5*dim6+ min(index_set_2of6(x))*dim3*dim4*dim5*dim6+ min(index_set_3of6(x))*dim4*dim5*dim6+ min(index_set_4of6(x))*dim5*dim6+ min(index_set_5of6(x))*dim6+ min(index_set_6of6(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of6(x); constraint idx2 in index_set_2of6(x); constraint idx3 in index_set_3of6(x); constraint idx4 in index_set_4of6(x); constraint idx5 in index_set_5of6(x); constraint idx6 in index_set_6of6(x); } in element_t( (idx1*(dim2*dim3*dim4*dim5*dim6)+idx2*(dim3*dim4*dim5*dim6)+idx3*(dim4*dim5*dim6)+idx4*(dim5*dim6)+idx5*dim6+idx6-min)::domain, array1d(x)) elseif ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of6(x)) /\ ub(idx1) <= max(index_set_1of6(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of6(x)) /\ ub(idx2) <= max(index_set_2of6(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of6(x)) /\ ub(idx3) <= max(index_set_3of6(x))) /\ (has_bounds(idx4) /\ lb(idx4) >= min(index_set_4of6(x)) /\ ub(idx4) <= max(index_set_4of6(x))) /\ (has_bounds(idx5) /\ lb(idx5) >= min(index_set_5of6(x)) /\ ub(idx5) <= max(index_set_5of6(x))) /\ (has_bounds(idx6) /\ lb(idx6) >= min(index_set_6of6(x)) /\ ub(idx6) <= max(index_set_6of6(x))) ) then element_t( (idx1*(dim2*dim3*dim4*dim5*dim6)+idx2*(dim3*dim4*dim5*dim6)+idx3*(dim4*dim5*dim6)+idx4*(dim5*dim6)+idx5*dim6+idx6-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of6(x); constraint idx2 in index_set_2of6(x); constraint idx3 in index_set_3of6(x); constraint idx4 in index_set_4of6(x); constraint idx5 in index_set_5of6(x); constraint idx6 in index_set_6of6(x); } in element_mt( (idx1*(dim2*dim3*dim4*dim5*dim6)+idx2*(dim3*dim4*dim5*dim6)+idx3*(dim4*dim5*dim6)+idx4*(dim5*dim6)+idx5*dim6+idx6-min)::domain, array1d(x)) endif; %%%%%%%%%%%%%%%%%%% % Element on floats function var float: element_t(var int: idx, array[int] of var float: x) :: promise_total = let { var lb_array(x)..ub_array(x): r ::is_defined_var; constraint idx in index_set(x); constraint array_var_float_element_nonshifted(idx,x,r) ::defines_var(r); } in r; function var float: element_mt(var int: idx, array[int] of var float: x) :: promise_total = let { var lb_array(x)..ub_array(x): r ::is_defined_var; var min(index_set(x))..max(index_set(x)): idx2; constraint idx in index_set(x) -> idx2=idx; constraint idx in index_set(x) \/ idx2=min(index_set(x)); constraint array_var_float_element_nonshifted(idx2,x,r) ::defines_var(r); } in r; function var float: element(var int: idx, array[int] of var float: x) = if mzn_in_root_context(idx) then let { constraint idx in index_set(x) } in element_t(idx,x) elseif (has_bounds(idx) /\ lb(idx) >= min(index_set(x)) /\ ub(idx) <= max(index_set(x))) then element_t(idx,x) else let { constraint idx in index_set(x) } in element_mt(idx,x) endif; function var float: element(var int: idx1, var int: idx2, array[int,int] of var float: x) = let { int: dim = card(index_set_2of2(x)); int: min_flat = min(index_set_1of2(x))*dim+min(index_set_2of2(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of2(x); constraint idx2 in index_set_2of2(x); } in element_t( (idx1*dim+idx2-min_flat)::domain, array1d(x)) elseif ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of2(x)) /\ ub(idx1) <= max(index_set_1of2(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of2(x)) /\ ub(idx2) <= max(index_set_2of2(x))) ) then element_t( (idx1*dim+idx2-min_flat)::domain, array1d(x)) else let { constraint idx1 in index_set_1of2(x); constraint idx2 in index_set_2of2(x); } in element_mt( (idx1*dim+idx2-min_flat)::domain, array1d(x)) endif; function var float: element(var int: idx1, var int: idx2, var int: idx3, array[int,int,int] of var float: x) = let { int: dim2 = card(index_set_2of3(x)); int: dim3 = card(index_set_3of3(x)); int: min = min(index_set_1of3(x))*dim2*dim3+ min(index_set_2of3(x))*dim3+ min(index_set_3of3(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of3(x); constraint idx2 in index_set_2of3(x); constraint idx3 in index_set_3of3(x); } in element_t( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) elseif ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of3(x)) /\ ub(idx1) <= max(index_set_1of3(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of3(x)) /\ ub(idx2) <= max(index_set_2of3(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of3(x)) /\ ub(idx3) <= max(index_set_3of3(x))) ) then element_t( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of3(x); constraint idx2 in index_set_2of3(x); constraint idx3 in index_set_3of3(x); } in element_mt( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) endif; function var float: element(var int: idx1, var int: idx2, var int: idx3, var int: idx4, array[int,int,int,int] of var float: x) = let { int: dim2 = card(index_set_2of4(x)); int: dim3 = card(index_set_3of4(x)); int: dim4 = card(index_set_4of4(x)); int: min = min(index_set_1of4(x))*dim2*dim3*dim4+ min(index_set_2of4(x))*dim3*dim4+ min(index_set_3of4(x))*dim4+ min(index_set_4of4(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of4(x); constraint idx2 in index_set_2of4(x); constraint idx3 in index_set_3of4(x); constraint idx4 in index_set_4of4(x); } in element_t( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) elseif ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of4(x)) /\ ub(idx1) <= max(index_set_1of4(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of4(x)) /\ ub(idx2) <= max(index_set_2of4(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of4(x)) /\ ub(idx3) <= max(index_set_3of4(x))) /\ (has_bounds(idx4) /\ lb(idx4) >= min(index_set_4of4(x)) /\ ub(idx4) <= max(index_set_4of4(x))) ) then element_t( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of4(x); constraint idx2 in index_set_2of4(x); constraint idx3 in index_set_3of4(x); constraint idx4 in index_set_4of4(x); } in element_mt( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) endif; function var float: element(var int: idx1, var int: idx2, var int: idx3, var int: idx4, var int: idx5, array[int,int,int,int,int] of var float: x) = let { int: dim2 = card(index_set_2of5(x)); int: dim3 = card(index_set_3of5(x)); int: dim4 = card(index_set_4of5(x)); int: dim5 = card(index_set_5of5(x)); int: min = min(index_set_1of5(x))*dim2*dim3*dim4*dim5+ min(index_set_2of5(x))*dim3*dim4*dim5+ min(index_set_3of5(x))*dim4*dim5+ min(index_set_4of5(x))*dim5+ min(index_set_5of5(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of5(x); constraint idx2 in index_set_2of5(x); constraint idx3 in index_set_3of5(x); constraint idx4 in index_set_4of5(x); constraint idx5 in index_set_5of5(x); } in element_t( (idx1*(dim2*dim3*dim4*dim5)+idx2*(dim3*dim4*dim5)+idx3*(dim4*dim5)+idx4*dim5+idx5-min)::domain, array1d(x)) elseif ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of5(x)) /\ ub(idx1) <= max(index_set_1of5(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of5(x)) /\ ub(idx2) <= max(index_set_2of5(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of5(x)) /\ ub(idx3) <= max(index_set_3of5(x))) /\ (has_bounds(idx4) /\ lb(idx4) >= min(index_set_4of5(x)) /\ ub(idx4) <= max(index_set_4of5(x))) /\ (has_bounds(idx5) /\ lb(idx5) >= min(index_set_5of5(x)) /\ ub(idx5) <= max(index_set_5of5(x))) ) then element_t( (idx1*(dim2*dim3*dim4*dim5)+idx2*(dim3*dim4*dim5)+idx3*(dim4*dim5)+idx4*dim5+idx5-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of5(x); constraint idx2 in index_set_2of5(x); constraint idx3 in index_set_3of5(x); constraint idx4 in index_set_4of5(x); constraint idx5 in index_set_5of5(x); } in element_mt( (idx1*(dim2*dim3*dim4*dim5)+idx2*(dim3*dim4*dim5)+idx3*(dim4*dim5)+idx4*dim5+idx5-min)::domain, array1d(x)) endif; function var float: element(var int: idx1, var int: idx2, var int: idx3, var int: idx4, var int: idx5, var int: idx6, array[int,int,int,int,int,int] of var float: x) = let { int: dim2 = card(index_set_2of6(x)); int: dim3 = card(index_set_3of6(x)); int: dim4 = card(index_set_4of6(x)); int: dim5 = card(index_set_5of6(x)); int: dim6 = card(index_set_6of6(x)); int: min = min(index_set_1of6(x))*dim2*dim3*dim4*dim5*dim6+ min(index_set_2of6(x))*dim3*dim4*dim5*dim6+ min(index_set_3of6(x))*dim4*dim5*dim6+ min(index_set_4of6(x))*dim5*dim6+ min(index_set_5of6(x))*dim6+ min(index_set_6of6(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of6(x); constraint idx2 in index_set_2of6(x); constraint idx3 in index_set_3of6(x); constraint idx4 in index_set_4of6(x); constraint idx5 in index_set_5of6(x); constraint idx6 in index_set_6of6(x); } in element_t( (idx1*(dim2*dim3*dim4*dim5*dim6)+idx2*(dim3*dim4*dim5*dim6)+idx3*(dim4*dim5*dim6)+idx4*(dim5*dim6)+idx5*dim6+idx6-min)::domain, array1d(x)) elseif ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of6(x)) /\ ub(idx1) <= max(index_set_1of6(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of6(x)) /\ ub(idx2) <= max(index_set_2of6(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of6(x)) /\ ub(idx3) <= max(index_set_3of6(x))) /\ (has_bounds(idx4) /\ lb(idx4) >= min(index_set_4of6(x)) /\ ub(idx4) <= max(index_set_4of6(x))) /\ (has_bounds(idx5) /\ lb(idx5) >= min(index_set_5of6(x)) /\ ub(idx5) <= max(index_set_5of6(x))) /\ (has_bounds(idx6) /\ lb(idx6) >= min(index_set_6of6(x)) /\ ub(idx6) <= max(index_set_6of6(x))) ) then element_t( (idx1*(dim2*dim3*dim4*dim5*dim6)+idx2*(dim3*dim4*dim5*dim6)+idx3*(dim4*dim5*dim6)+idx4*(dim5*dim6)+idx5*dim6+idx6-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of6(x); constraint idx2 in index_set_2of6(x); constraint idx3 in index_set_3of6(x); constraint idx4 in index_set_4of6(x); constraint idx5 in index_set_5of6(x); constraint idx6 in index_set_6of6(x); } in element_mt( (idx1*(dim2*dim3*dim4*dim5*dim6)+idx2*(dim3*dim4*dim5*dim6)+idx3*(dim4*dim5*dim6)+idx4*(dim5*dim6)+idx5*dim6+idx6-min)::domain, array1d(x)) endif; %%%%%%%%%%%%%%%%% % Element on sets function var set of int: element_t(var int: idx, array[int] of var set of int: x) :: promise_total = let { var set of min(ub_array(x))..max(ub_array(x)): r ::is_defined_var; constraint idx in index_set(x); constraint array_var_set_element_nonshifted(idx,x,r) ::defines_var(r); } in r; function var set of int: element_mt(var int: idx, array[int] of var set of int: x) :: promise_total = let { var set of min(ub_array(x))..max(ub_array(x)): r ::is_defined_var; var min(index_set(x))..max(index_set(x)): idx2; constraint idx in index_set(x) -> idx2=idx; constraint idx in index_set(x) \/ idx2=min(index_set(x)); constraint array_var_set_element_nonshifted(idx2,x,r) ::defines_var(r); } in r; function var set of int: element(var int: idx, array[int] of var set of int: x) = if mzn_in_root_context(idx) then let { constraint idx in index_set(x) } in element_t(idx,x) elseif (has_bounds(idx) /\ lb(idx) >= min(index_set(x)) /\ ub(idx) <= max(index_set(x))) then element_t(idx,x) else let { constraint idx in index_set(x) } in element_mt(idx,x) endif; function var set of int: element(var int: idx1, var int: idx2, array[int,int] of var set of int: x) = let { int: dim = card(index_set_2of2(x)); int: min_flat = min(index_set_1of2(x))*dim+min(index_set_2of2(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of2(x); constraint idx2 in index_set_2of2(x); } in element_t( (idx1*dim+idx2-min_flat)::domain, array1d(x)) elseif ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of2(x)) /\ ub(idx1) <= max(index_set_1of2(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of2(x)) /\ ub(idx2) <= max(index_set_2of2(x))) ) then element_t( (idx1*dim+idx2-min_flat)::domain, array1d(x)) else let { constraint idx1 in index_set_1of2(x); constraint idx2 in index_set_2of2(x); } in element_mt( (idx1*dim+idx2-min_flat)::domain, array1d(x)) endif; function var set of int: element(var int: idx1, var int: idx2, var int: idx3, array[int,int,int] of var set of int: x) = let { int: dim2 = card(index_set_2of3(x)); int: dim3 = card(index_set_3of3(x)); int: min = min(index_set_1of3(x))*dim2*dim3+ min(index_set_2of3(x))*dim3+ min(index_set_3of3(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of3(x); constraint idx2 in index_set_2of3(x); constraint idx3 in index_set_3of3(x); } in element_t( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) elseif ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of3(x)) /\ ub(idx1) <= max(index_set_1of3(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of3(x)) /\ ub(idx2) <= max(index_set_2of3(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of3(x)) /\ ub(idx3) <= max(index_set_3of3(x))) ) then element_t( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of3(x); constraint idx2 in index_set_2of3(x); constraint idx3 in index_set_3of3(x); } in element_mt( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) endif; function var set of int: element(var int: idx1, var int: idx2, var int: idx3, var int: idx4, array[int,int,int,int] of var set of int: x) = let { int: dim2 = card(index_set_2of4(x)); int: dim3 = card(index_set_3of4(x)); int: dim4 = card(index_set_4of4(x)); int: min = min(index_set_1of4(x))*dim2*dim3*dim4+ min(index_set_2of4(x))*dim3*dim4+ min(index_set_3of4(x))*dim4+ min(index_set_4of4(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of4(x); constraint idx2 in index_set_2of4(x); constraint idx3 in index_set_3of4(x); constraint idx4 in index_set_4of4(x); } in element_t( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) elseif ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of4(x)) /\ ub(idx1) <= max(index_set_1of4(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of4(x)) /\ ub(idx2) <= max(index_set_2of4(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of4(x)) /\ ub(idx3) <= max(index_set_3of4(x))) /\ (has_bounds(idx4) /\ lb(idx4) >= min(index_set_4of4(x)) /\ ub(idx4) <= max(index_set_4of4(x))) ) then element_t( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of4(x); constraint idx2 in index_set_2of4(x); constraint idx3 in index_set_3of4(x); constraint idx4 in index_set_4of4(x); } in element_mt( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) endif; function var set of int: element(var int: idx1, var int: idx2, var int: idx3, var int: idx4, var int: idx5, array[int,int,int,int,int] of var set of int: x) = let { int: dim2 = card(index_set_2of5(x)); int: dim3 = card(index_set_3of5(x)); int: dim4 = card(index_set_4of5(x)); int: dim5 = card(index_set_5of5(x)); int: min = min(index_set_1of5(x))*dim2*dim3*dim4*dim5+ min(index_set_2of5(x))*dim3*dim4*dim5+ min(index_set_3of5(x))*dim4*dim5+ min(index_set_4of5(x))*dim5+ min(index_set_5of5(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of5(x); constraint idx2 in index_set_2of5(x); constraint idx3 in index_set_3of5(x); constraint idx4 in index_set_4of5(x); constraint idx5 in index_set_5of5(x); } in element_t( (idx1*(dim2*dim3*dim4*dim5)+idx2*(dim3*dim4*dim5)+idx3*(dim4*dim5)+idx4*dim5+idx5-min)::domain, array1d(x)) elseif ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of5(x)) /\ ub(idx1) <= max(index_set_1of5(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of5(x)) /\ ub(idx2) <= max(index_set_2of5(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of5(x)) /\ ub(idx3) <= max(index_set_3of5(x))) /\ (has_bounds(idx4) /\ lb(idx4) >= min(index_set_4of5(x)) /\ ub(idx4) <= max(index_set_4of5(x))) /\ (has_bounds(idx5) /\ lb(idx5) >= min(index_set_5of5(x)) /\ ub(idx5) <= max(index_set_5of5(x))) ) then element_t( (idx1*(dim2*dim3*dim4*dim5)+idx2*(dim3*dim4*dim5)+idx3*(dim4*dim5)+idx4*dim5+idx5-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of5(x); constraint idx2 in index_set_2of5(x); constraint idx3 in index_set_3of5(x); constraint idx4 in index_set_4of5(x); constraint idx5 in index_set_5of5(x); } in element_mt( (idx1*(dim2*dim3*dim4*dim5)+idx2*(dim3*dim4*dim5)+idx3*(dim4*dim5)+idx4*dim5+idx5-min)::domain, array1d(x)) endif; function var set of int: element(var int: idx1, var int: idx2, var int: idx3, var int: idx4, var int: idx5, var int: idx6, array[int,int,int,int,int,int] of var set of int: x) = let { int: dim2 = card(index_set_2of6(x)); int: dim3 = card(index_set_3of6(x)); int: dim4 = card(index_set_4of6(x)); int: dim5 = card(index_set_5of6(x)); int: dim6 = card(index_set_6of6(x)); int: min = min(index_set_1of6(x))*dim2*dim3*dim4*dim5*dim6+ min(index_set_2of6(x))*dim3*dim4*dim5*dim6+ min(index_set_3of6(x))*dim4*dim5*dim6+ min(index_set_4of6(x))*dim5*dim6+ min(index_set_5of6(x))*dim6+ min(index_set_6of6(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of6(x); constraint idx2 in index_set_2of6(x); constraint idx3 in index_set_3of6(x); constraint idx4 in index_set_4of6(x); constraint idx5 in index_set_5of6(x); constraint idx6 in index_set_6of6(x); } in element_t( (idx1*(dim2*dim3*dim4*dim5*dim6)+idx2*(dim3*dim4*dim5*dim6)+idx3*(dim4*dim5*dim6)+idx4*(dim5*dim6)+idx5*dim6+idx6-min)::domain, array1d(x)) elseif ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of6(x)) /\ ub(idx1) <= max(index_set_1of6(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of6(x)) /\ ub(idx2) <= max(index_set_2of6(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of6(x)) /\ ub(idx3) <= max(index_set_3of6(x))) /\ (has_bounds(idx4) /\ lb(idx4) >= min(index_set_4of6(x)) /\ ub(idx4) <= max(index_set_4of6(x))) /\ (has_bounds(idx5) /\ lb(idx5) >= min(index_set_5of6(x)) /\ ub(idx5) <= max(index_set_5of6(x))) /\ (has_bounds(idx6) /\ lb(idx6) >= min(index_set_6of6(x)) /\ ub(idx6) <= max(index_set_6of6(x))) ) then element_t( (idx1*(dim2*dim3*dim4*dim5*dim6)+idx2*(dim3*dim4*dim5*dim6)+idx3*(dim4*dim5*dim6)+idx4*(dim5*dim6)+idx5*dim6+idx6-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of6(x); constraint idx2 in index_set_2of6(x); constraint idx3 in index_set_3of6(x); constraint idx4 in index_set_4of6(x); constraint idx5 in index_set_5of6(x); constraint idx6 in index_set_6of6(x); } in element_mt( (idx1*(dim2*dim3*dim4*dim5*dim6)+idx2*(dim3*dim4*dim5*dim6)+idx3*(dim4*dim5*dim6)+idx4*(dim5*dim6)+idx5*dim6+idx6-min)::domain, array1d(x)) endif; %%%%%%%%%%%%%%%%%% % Element on bools function var bool: element_t(var int: idx, array[int] of var bool: x) :: promise_total = let { var bool: r ::is_defined_var; constraint idx in index_set(x); constraint array_var_bool_element_nonshifted(idx,x,r) ::defines_var(r); } in r; function var bool: element_mt(var int: idx, array[int] of var bool: x) :: promise_total = let { var bool: r ::is_defined_var; var min(index_set(x))..max(index_set(x)): idx2; constraint idx in index_set(x) -> idx2=idx; constraint idx in index_set(x) \/ idx2=min(index_set(x)); constraint array_var_bool_element_nonshifted(idx2,x,r) ::defines_var(r); } in r; function var bool: element(var int: idx, array[int] of var bool: x) = if mzn_in_root_context(idx) then idx in index_set(x) /\ element_t(idx,x) elseif (has_bounds(idx) /\ lb(idx) >= min(index_set(x)) /\ ub(idx) <= max(index_set(x))) then element_t(idx,x) else idx in index_set(x) /\ element_mt(idx,x) endif; function var bool: element(var int: idx1, var int: idx2, array[int,int] of var bool: x) = let { int: dim = card(index_set_2of2(x)); int: min_flat = min(index_set_1of2(x))*dim+min(index_set_2of2(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of2(x); constraint idx2 in index_set_2of2(x); } in element_t( (idx1*dim+idx2-min_flat)::domain, array1d(x)) elseif ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of2(x)) /\ ub(idx1) <= max(index_set_1of2(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of2(x)) /\ ub(idx2) <= max(index_set_2of2(x))) ) then element_t( (idx1*dim+idx2-min_flat)::domain, array1d(x)) else let { constraint idx1 in index_set_1of2(x); constraint idx2 in index_set_2of2(x); } in element_mt( (idx1*dim+idx2-min_flat)::domain, array1d(x)) endif; function var bool: element(var int: idx1, var int: idx2, var int: idx3, array[int,int,int] of var bool: x) = let { int: dim2 = card(index_set_2of3(x)); int: dim3 = card(index_set_3of3(x)); int: min = min(index_set_1of3(x))*dim2*dim3+ min(index_set_2of3(x))*dim3+ min(index_set_3of3(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of3(x); constraint idx2 in index_set_2of3(x); constraint idx3 in index_set_3of3(x); } in element_t( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) elseif ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of3(x)) /\ ub(idx1) <= max(index_set_1of3(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of3(x)) /\ ub(idx2) <= max(index_set_2of3(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of3(x)) /\ ub(idx3) <= max(index_set_3of3(x))) ) then element_t( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of3(x); constraint idx2 in index_set_2of3(x); constraint idx3 in index_set_3of3(x); } in element_mt( (idx1*(dim2*dim3)+idx2*dim3+idx3-min)::domain, array1d(x)) endif; function var bool: element(var int: idx1, var int: idx2, var int: idx3, var int: idx4, array[int,int,int,int] of var bool: x) = let { int: dim2 = card(index_set_2of4(x)); int: dim3 = card(index_set_3of4(x)); int: dim4 = card(index_set_4of4(x)); int: min = min(index_set_1of4(x))*dim2*dim3*dim4+ min(index_set_2of4(x))*dim3*dim4+ min(index_set_3of4(x))*dim4+ min(index_set_4of4(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of4(x); constraint idx2 in index_set_2of4(x); constraint idx3 in index_set_3of4(x); constraint idx4 in index_set_4of4(x); } in element_t( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) elseif ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of4(x)) /\ ub(idx1) <= max(index_set_1of4(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of4(x)) /\ ub(idx2) <= max(index_set_2of4(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of4(x)) /\ ub(idx3) <= max(index_set_3of4(x))) /\ (has_bounds(idx4) /\ lb(idx4) >= min(index_set_4of4(x)) /\ ub(idx4) <= max(index_set_4of4(x))) ) then element_t( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of4(x); constraint idx2 in index_set_2of4(x); constraint idx3 in index_set_3of4(x); constraint idx4 in index_set_4of4(x); } in element_mt( (idx1*(dim2*dim3*dim4)+idx2*(dim3*dim4)+idx3*dim4+idx4-min)::domain, array1d(x)) endif; function var bool: element(var int: idx1, var int: idx2, var int: idx3, var int: idx4, var int: idx5, array[int,int,int,int,int] of var bool: x) = let { int: dim2 = card(index_set_2of5(x)); int: dim3 = card(index_set_3of5(x)); int: dim4 = card(index_set_4of5(x)); int: dim5 = card(index_set_5of5(x)); int: min = min(index_set_1of5(x))*dim2*dim3*dim4*dim5+ min(index_set_2of5(x))*dim3*dim4*dim5+ min(index_set_3of5(x))*dim4*dim5+ min(index_set_4of5(x))*dim5+ min(index_set_5of5(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of5(x); constraint idx2 in index_set_2of5(x); constraint idx3 in index_set_3of5(x); constraint idx4 in index_set_4of5(x); constraint idx5 in index_set_5of5(x); } in element_t( (idx1*(dim2*dim3*dim4*dim5)+idx2*(dim3*dim4*dim5)+idx3*(dim4*dim5)+idx4*dim5+idx5-min)::domain, array1d(x)) elseif ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of5(x)) /\ ub(idx1) <= max(index_set_1of5(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of5(x)) /\ ub(idx2) <= max(index_set_2of5(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of5(x)) /\ ub(idx3) <= max(index_set_3of5(x))) /\ (has_bounds(idx4) /\ lb(idx4) >= min(index_set_4of5(x)) /\ ub(idx4) <= max(index_set_4of5(x))) /\ (has_bounds(idx5) /\ lb(idx5) >= min(index_set_5of5(x)) /\ ub(idx5) <= max(index_set_5of5(x))) ) then element_t( (idx1*(dim2*dim3*dim4*dim5)+idx2*(dim3*dim4*dim5)+idx3*(dim4*dim5)+idx4*dim5+idx5-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of5(x); constraint idx2 in index_set_2of5(x); constraint idx3 in index_set_3of5(x); constraint idx4 in index_set_4of5(x); constraint idx5 in index_set_5of5(x); } in element_mt( (idx1*(dim2*dim3*dim4*dim5)+idx2*(dim3*dim4*dim5)+idx3*(dim4*dim5)+idx4*dim5+idx5-min)::domain, array1d(x)) endif; function var bool: element(var int: idx1, var int: idx2, var int: idx3, var int: idx4, var int: idx5, var int: idx6, array[int,int,int,int,int,int] of var bool: x) = let { int: dim2 = card(index_set_2of6(x)); int: dim3 = card(index_set_3of6(x)); int: dim4 = card(index_set_4of6(x)); int: dim5 = card(index_set_5of6(x)); int: dim6 = card(index_set_6of6(x)); int: min = min(index_set_1of6(x))*dim2*dim3*dim4*dim5*dim6+ min(index_set_2of6(x))*dim3*dim4*dim5*dim6+ min(index_set_3of6(x))*dim4*dim5*dim6+ min(index_set_4of6(x))*dim5*dim6+ min(index_set_5of6(x))*dim6+ min(index_set_6of6(x))-1; } in if mzn_in_root_context(idx1) then let { constraint idx1 in index_set_1of6(x); constraint idx2 in index_set_2of6(x); constraint idx3 in index_set_3of6(x); constraint idx4 in index_set_4of6(x); constraint idx5 in index_set_5of6(x); constraint idx6 in index_set_6of6(x); } in element_t( (idx1*(dim2*dim3*dim4*dim5*dim6)+idx2*(dim3*dim4*dim5*dim6)+idx3*(dim4*dim5*dim6)+idx4*(dim5*dim6)+idx5*dim6+idx6-min)::domain, array1d(x)) elseif ( (has_bounds(idx1) /\ lb(idx1) >= min(index_set_1of6(x)) /\ ub(idx1) <= max(index_set_1of6(x))) /\ (has_bounds(idx2) /\ lb(idx2) >= min(index_set_2of6(x)) /\ ub(idx2) <= max(index_set_2of6(x))) /\ (has_bounds(idx3) /\ lb(idx3) >= min(index_set_3of6(x)) /\ ub(idx3) <= max(index_set_3of6(x))) /\ (has_bounds(idx4) /\ lb(idx4) >= min(index_set_4of6(x)) /\ ub(idx4) <= max(index_set_4of6(x))) /\ (has_bounds(idx5) /\ lb(idx5) >= min(index_set_5of6(x)) /\ ub(idx5) <= max(index_set_5of6(x))) /\ (has_bounds(idx6) /\ lb(idx6) >= min(index_set_6of6(x)) /\ ub(idx6) <= max(index_set_6of6(x))) ) then element_t( (idx1*(dim2*dim3*dim4*dim5*dim6)+idx2*(dim3*dim4*dim5*dim6)+idx3*(dim4*dim5*dim6)+idx4*(dim5*dim6)+idx5*dim6+idx6-min)::domain, array1d(x)) else let { constraint idx1 in index_set_1of6(x); constraint idx2 in index_set_2of6(x); constraint idx3 in index_set_3of6(x); constraint idx4 in index_set_4of6(x); constraint idx5 in index_set_5of6(x); constraint idx6 in index_set_6of6(x); } in element_mt( (idx1*(dim2*dim3*dim4*dim5*dim6)+idx2*(dim3*dim4*dim5*dim6)+idx3*(dim4*dim5*dim6)+idx4*(dim5*dim6)+idx5*dim6+idx6-min)::domain, array1d(x)) endif; %-----------------------------------------------------------------------------% % % Internal functions for implementing div, mod etc function set of int:compute_div_bounds(var int: x, var int: y); function var int: div_t(var int: x, var int: y) :: promise_total = let { var (compute_div_bounds(x,y)): z ::is_defined_var; constraint y != 0; constraint int_div(x,y,z) ::defines_var(z); } in z; function var int: div_mt(var int: x, var int: y) :: promise_total = let { var ((dom(y) diff {0}) union {1}): yy = if y=0 then 1 else y endif; } in div_t(x,yy); function var float: fldiv_t(var float: x, float: y) :: promise_total = x*(1.0/y); function var float: fldiv_t(var float: x, var float: y) :: promise_total = let { var float: z ::is_defined_var; % TODO: Compute division boundaries constraint if lb(y) <= 0 /\ ub(y) >= 0 then y != 0.0 endif; constraint float_div(x, y, z) ::defines_var(z); } in z; function var float: fldiv_mt(var float: x, var float: y) :: promise_total = let { var (lb(y)..ub(y) diff {0.0}) union {1.0}: yy = if (y = 0.0) then 1.0 else y endif; } in fldiv_t(x, yy); function var int: mod_t(var int: x, var int: y) :: promise_total = let { var -(max(ub(y),-lb(y)))..max(ub(y),-lb(y)): z; constraint y != 0; constraint int_mod(x,y,z); } in z; function var int: mod_mt(var int: x, var int: y) :: promise_total = let { var {1} union dom(y): yy = if y=0 then 1 else y endif; } in mod_t(x,yy); function var int: product_rec(array[int] of var int: x) = if length(x)=0 then 1 elseif length(x)=1 then x[min(index_set(x))] else let { array[int] of var int: xx = array1d(x); array[index_set(xx)] of var int: y; constraint y[1] = xx[1]; constraint forall (i in 2..length(y)) (y[i]=y[i-1]*xx[i]); } in y[length(y)] endif; function var float: product_rec(array[int] of var float: x) = if length(x)=0 then 1.0 elseif length(x)=1 then x[min(index_set(x))] else let { array[int] of var float: xx = array1d(x); array[index_set(xx)] of var float: y; constraint y[1] = xx[1]; constraint forall (i in 2..length(y)) (y[i]=y[i-1]*xx[i]); } in y[length(y)] endif; function var int: max_t(array[int] of var int: x) :: promise_total = if length(x)=0 then 0 elseif length(x)=1 then x[min(index_set(x))] elseif length(x)=2 then max(x[1],x[2]) else let { var lb_array(x)..ub_array(x): m ::is_defined_var; constraint array_int_maximum(m,x) ::defines_var(m); } in m endif; function var int: min_t(array[int] of var int: x) :: promise_total = if length(x)=0 then 0 elseif length(x)=1 then x[1] elseif length(x)=2 then min(x[1],x[2]) else let { var lb_array(x)..ub_array(x): m ::is_defined_var; constraint array_int_minimum(m,x) ::defines_var(m); } in m endif; function var float: max_t(array[int] of var float: x) :: promise_total = if length(x)=0 then 0.0 elseif length(x)=1 then x[min(index_set(x))] elseif length(x)=2 then max(x[1],x[2]) else let { var lb_array(x)..ub_array(x): m ::is_defined_var; constraint array_float_maximum(m,x) ::defines_var(m); } in m endif; function var float: min_t(array[int] of var float: x) :: promise_total = if length(x)=0 then 0.0 elseif length(x)=1 then x[1] elseif length(x)=2 then min(x[1],x[2]) else let { var lb_array(x)..ub_array(x): m ::is_defined_var; constraint array_float_minimum(m,x) ::defines_var(m); } in m endif; /*** @groupdef builtins.random Random Number Generator builtins These functions implement random number generators from different probability distributions. */ /** @group builtins.random Return a sample from the normal distribution defined by \(\a mean, \a std\) */ function float: normal(float: mean, float: std); /** @group builtins.random Return a sample from the normal distribution defined by \(\a mean, \a std\) */ function float: normal(int: mean, float: std); /** @group builtins.random Return a sample from the uniform distribution defined by \(\a lowerbound, \a upperbound\) */ function float: uniform(float: lowerbound, float: upperbound); /** @group builtins.random Return a sample from the uniform distribution defined by \(\a lowerbound, \a upperbound\) */ function int: uniform(int: lowerbound, int: upperbound); /** @group builtins.random Return a sample from the poisson distribution defined by \a mean */ function int: poisson(float: mean); /** @group builtins.random Return a sample from the poisson distribution defined by an integer \a mean */ function int: poisson(int: mean); /** @group builtins.random Return a sample from the gamma distribution defined by \(\a alpha, \a beta\) */ function float: gamma(float: alpha, float: beta); /** @group builtins.random Return a sample from the gamma distribution defined by \(\a alpha, \a beta\) */ function float: gamma(int: alpha, float: beta); /** @group builtins.random Return a sample from the Weibull distribution defined by \(\a shape, \a scale\) */ function float: weibull(float: shape, float: scale); /** @group builtins.random Return a sample from the Weibull distribution defined by \(\a shape, \a scale\) */ function float: weibull(int: shape, float: scale); /** @group builtins.random Return a sample from the exponential distribution defined by \(\a lambda\) */ function float: exponential(int: lambda); /** @group builtins.random Return a sample from the exponential distribution defined by \(\a lambda\) */ function float: exponential(float: lambda); /** @group builtins.random Return a sample from the lognormal distribution defined by \(\a mean, \a std\) */ function float: lognormal(float: mean, float: std); /** @group builtins.random Return a sample from the lognormal distribution defined by \(\a mean, \a std\) */ function float: lognormal(int: mean, float: std); /** @group builtins.random Return a sample from the chi-squared distribution defined by the degree of freedom \(\a n\) */ function float: chisquared(int: n); /** @group builtins.random Return a sample from the chi-squared distribution defined by the degree of freedom \(\a n\) */ function float: chisquared(float: n); /** @group builtins.random Return a sample from the cauchy distribution defined by \(\a mean, \a scale\) */ function float: cauchy(float: mean, float: scale); /** @group builtins.random Return a sample from the cauchy distribution defined by \(\a mean, \a scale\) */ function float: cauchy(int: mean, float: scale); /** @group builtins.random Return a sample from the Fisher-Snedecor F-distribution defined by the degrees of freedom \(\a d1, \a d2\) */ function float: fdistribution(float: d1, float: d2); /** @group builtins.random Return a sample from the Fisher-Snedecor F-distribution defined by the degrees of freedom \(\a d1, \a d2\) */ function float: fdistribution(int: d1, int: d2); /** @group builtins.random Return a sample from the student's t-distribution defined by the sample size \(\a n\) */ function float: tdistribution(float: n); /** @group builtins.random Return a sample from the student's t-distribution defined by the sample size \(\a n\) */ function float: tdistribution(int: n); /** @group builtins.random Return a sample from the discrete distribution defined by the array of weights \(\a weights\) that assigns a weight to each integer starting from zero */ function int: discrete_distribution(array[int] of int: weights); /** @group builtins.random Return a boolean sample from the Bernoulli distribution defined by probability \(\a p\) */ function bool: bernoulli(float: p); /** @group builtins.random Return a sample from the binomial distribution defined by sample number \a t and probability \a p */ function int: binomial(int: t, float: p); /*** @groupdef builtins.special Special constraints These predicates allow users to mark constraints as e.g. symmetry breaking or redundant, so that solvers can choose to implement them differently. We cannot easily use annotations for this purpose, since annotations are propagated to all constraints in a decomposition, which may be incorrect for redundant or symmetry breaking constraints in the presence of common subexpression elimination (CSE). */ /** @group builtins.special Mark \a b as a symmetry breaking constraint */ predicate symmetry_breaking_constraint(var bool: b); /** @group builtins.special Mark \a b as a redundant constraint */ predicate redundant_constraint(var bool: b); /** @group builtins.special Mark \a b as an implied constraint (synonym for redundant_constraint) */ predicate implied_constraint(var bool: b) = redundant_constraint(b); function set of int: anon_enum(int: n) = 1..n; function set of int: anon_enum(array[int] of string: x); /*** @groupdef builtins.language Language information These functions return information about the MiniZinc system. */ /** @group builtins.language Return MiniZinc version encoded as an integer (major*10000+minor*1000+patch). */ function int: mzn_compiler_version(); /** @group builtins.language Return string representation of \a v given an integer major*10000+minor*1000+patch */ function string: mzn_version_to_string(int: v) = show(v div 10000)++"."++show((v div 1000) mod 10)++"."++show(v mod 100); %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% % Include solver-specific redefinitions for any FlatZinc built-ins. % include "redefinitions.mzn"; include "redefinitions-2.0.mzn"; include "redefinitions-2.0.2.mzn"; include "redefinitions-2.1.mzn"; include "redefinitions-2.1.1.mzn"; include "redefinitions-2.2.1.mzn"; include "redefinitions-2.3.3.mzn"; include "fzn_if_then_else_int.mzn"; include "fzn_if_then_else_opt_int.mzn"; include "fzn_if_then_else_var_int.mzn"; include "fzn_if_then_else_var_opt_int.mzn"; include "fzn_if_then_else_bool.mzn"; include "fzn_if_then_else_opt_bool.mzn"; include "fzn_if_then_else_var_bool.mzn"; include "fzn_if_then_else_var_opt_bool.mzn"; include "fzn_if_then_else_float.mzn"; include "fzn_if_then_else_opt_float.mzn"; include "fzn_if_then_else_var_float.mzn"; include "fzn_if_then_else_var_opt_float.mzn"; include "fzn_if_then_else_set.mzn"; include "fzn_if_then_else_var_set.mzn"; include "fzn_if_then_else_partiality.mzn"; include "count_eq.mzn"; include "count_geq.mzn"; include "count_leq.mzn"; include "count_neq.mzn"; include "count_gt.mzn"; include "count_lt.mzn"; include "count_fn.mzn"; %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/circuit.mzn000066400000000000000000000006761360574160400217510ustar00rootroot00000000000000include "fzn_circuit.mzn"; include "fzn_circuit_reif.mzn"; /** @group globals Constrains the elements of \a x to define a circuit where \a x[\p i] = \p j means that \p j is the successor of \p i. */ predicate circuit(array[int] of var int: x) = fzn_circuit(x); predicate circuit_reif(array[int] of var int: x, var bool: b) = fzn_circuit_reif(x, b); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/comparison_rel_array.mzn000066400000000000000000000023071360574160400245120ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Reflect an array of comparison values onto a comparison value variable using % a lexicographic interpretation of the array. The comparison values are % encoded as follows: > | = | < as -1 | 0 | +1. % Uses of this constraint are generated by Cadmium transformations that % simplify ordering constraints on expressions of complex types. %-----------------------------------------------------------------------------% predicate comparison_rel_array(array[int] of var -1..1: rels, var -1..1: rel) = let { int: l = min(index_set(rels)), int: u = max(index_set(rels)), array[l-1..u] of var -1..1: r } in r[l-1] = 0 % initial state (before first array position) is 'equal' /\ forall (i in l..u) ( % new state: as given array at current position if % previous state is 'equal', otherwise previous state % % r[i] = (if r[i-1] = 0 then rels[i] else r[i-1] endif) (r[i-1] = 0 -> r[i] = rels[i]) /\ (r[i-1] != 0 -> r[i] = r[i-1]) ) /\ r[u] = rel; % final state (at last array position) libminizinc-2.4.2/share/minizinc/std/connected.mzn000066400000000000000000000040761360574160400222470ustar00rootroot00000000000000include "fzn_connected.mzn"; include "fzn_connected_reif.mzn"; include "fzn_dconnected.mzn"; include "fzn_dconnected_reif.mzn"; /** @group globals.graph Constrains the subgraph \a ns and \a es of a given directed graph to be connected. @param from: the leaving node for each edge @param to: the entering node for each edge @param ns: a Boolean for each node whether it is in the subgraph @param es: a Boolean for each edge whether it is in the subgraph */ predicate dconnected(array[int] of $$N: from, array[int] of $$N: to, array[$$N] of var bool: ns, array[int] of var bool: es) = assert(index_set(from) = index_set(to),"dconnected: index set of from and to must be identical") /\ assert(index_set(from) = index_set(es),"dconnected: index set of from and es must be identical") /\ assert(dom_array(from) subset index_set(ns),"dconnected: nodes in from must be in index set of ns") /\ assert(dom_array(from) subset index_set(ns),"dconnected: nodes in to must be in index set of ns") /\ fzn_dconnected(from,to,ns,es); %-----------------------------------------------------------------------------% /** @group globals.graph Constrains the subgraph \a ns and \a es of a given undirected graph to be connected. @param from: is the leaving node for each edge @param to: is the entering node for each edge @param ns: is a Boolean for each node whether it is in the subgraph @param es: is a Boolean for each edge whether it is in the subgraph */ predicate connected(array[int] of $$N: from, array[int] of $$N: to, array[$$N] of var bool: ns, array[int] of var bool: es) = assert(index_set(from) = index_set(to),"connected: index set of from and to must be identical") /\ assert(index_set(from) = index_set(es),"connected: index set of from and es must be identical") /\ assert(dom_array(from) subset index_set(ns),"connected: nodes in from must be in index set of ns") /\ assert(dom_array(from) subset index_set(ns),"connected: nodes in to must be in index set of ns") /\ fzn_connected(from,to,ns,es); libminizinc-2.4.2/share/minizinc/std/cost_mdd.mzn000066400000000000000000000111301360574160400220660ustar00rootroot00000000000000include "fzn_cost_mdd.mzn"; include "fzn_cost_mdd_reif.mzn"; /** @group globals.extensional Requires that \a x defines a path in the cost MDD with total edge weight \a totalcost. @param N: the number of nodes, the root node is node 1 @param level: the level of each node, the root is level 1, T is level \a length(x)+1 @param E: the number of edges @param from: the leaving node (1..\a N)for each edge @param label: the set of value of the x variable for each edge @param cost: the cost for each edge @param to: the entering node for each edge, where 0 = T node @param totalcost: the total cost of the path defined by \a x */ predicate cost_mdd(array[int] of var int: x, % variables constrained by MDD int: N, % number of nodes root is node 1 array[int] of int: level, % level of each node root is level 1, T is level length(x)+1 int: E, % number of edges array[int] of int: from, % edge leaving node 1..N array[int] of set of int: label, % values of variable on edge array[int] of int: cost, % cost of using edge array[int] of int: to, % edge entering node 0..N where 0 = T node var int: totalcost % total cost of path ) = let { set of int: NODE = 1..N; set of int: EDGE = 1..E; int: L = length(x); array[0..N] of int: levele = array1d(0..N,[L+1]++level); } in assert(index_set(level) = NODE, "cost_mdd: level argument must be of length N = \(N)") /\ assert(level[1] = 1, "cost_mdd: level of root (1) must be 1") /\ forall(n in 2..N)(assert(level[n] != 1, "cost_mdd: level of non root node (\(n)) must not be 1")) /\ assert(index_set(from) = EDGE, "cost_mdd: from argument must be of length E = \(E)") /\ assert(index_set(to) = EDGE, "cost_mdd: to argument must be of length E = \(E)") /\ assert(index_set(label) = EDGE, "cost_mdd: label argument must be of length E = \(E)") /\ assert(index_set(cost) = EDGE, "cost_mdd: cost argument must be of length E = \(E)") /\ forall(e in EDGE)(assert(from[e] in NODE, "cost_mdd: from[\(e)] must be in \(NODE)")) /\ forall(e in EDGE)(assert(to[e] in 0..N, "cost_mdd: to[\(e)] must be in 0..\(N)")) /\ forall(e in EDGE)(assert(level[from[e]]+1 = levele[to[e]], "cost_mdd: mdd level of from[\(e)] = \(level[from[e]])" ++ "must be 1 less than level of to[\(e)] = \(levele[to[e]])")) /\ forall(e1,e2 in EDGE where e1 < e2 /\ from[e1] = from[e2]) (assert(label[e1] intersect label[e2] = {}, "cost_mdd: Two edges \(e1) and \(e2) leaving node \(from[e1]) with overlapping labels")) /\ fzn_cost_mdd(x,N,level,E,from,label,cost,to,totalcost); predicate cost_mdd_reif(array[int] of var int: x, % variables constrained by MDD int: N, % number of nodes root is node 1 array[int] of int: level, % level of each node root is level 1, T is level length(x)+1 int: E, % number of edges array[int] of int: from, % edge leaving node 1..N array[int] of set of int: label, % values of variable on edge array[int] of int: cost, % cost of using edge array[int] of int: to, % edge entering node 0..N where 0 = T node var int: totalcost, % total cost of path var bool: b % reification variable ) = fzn_cost_mdd_reif(x, N, level, E, from, label, cost, to, totalcost, b); % Example consider an MDD over 3 variables % 5 nodes and 8 edges % level 1 root = 1 % level 2 2 3 % level 3 4 5 % level 4 T % with edges (from,label,cost,to) given by % (1,{1,3},3,2), (1,{2},1,3), % (2,{2},4,4), (2,{3},2,5), % (3,{3},3,4), (3,{2},5,5), % (4,{1,5},2,0), % (5,{2,4,6},4,0) % this is defined by the call % cost_mdd([x1,x2,x3],5,[1,2,2,3,3],8,[1,1,2,2,3,3,4,5], % [{1,3},{2},{2},{3},{3},{2},{1,5},{2,4,6}],[3,1,4,2,3,5,2,4],[2,3,4,5,4,5,0,0],tc) libminizinc-2.4.2/share/minizinc/std/cost_regular.mzn000066400000000000000000000032741360574160400227750ustar00rootroot00000000000000include "fzn_cost_regular.mzn"; include "fzn_cost_regular_reif.mzn"; /** @group globals.extensional The sequence of values in array \a x (which must all be in the range 1..\a S) is accepted by the DFA of \a Q states with input 1..\a S and transition function \a d (which maps (1..\a Q, 1..\a S) -> 0..\a Q)) and initial state \a q0 (which must be in 1..\a Q) and accepting states \a F (which all must be in 1..\a Q). We reserve state 0 to be an always failing state. Each edge has an associated cost \a c, and \a C is the sum of costs taken on the accepting path for \a x. */ predicate cost_regular(array[int] of var int: x, int: Q, int: S, array[int,int] of int: d, int: q0, set of int: F, array[int,int] of int: c, var int: C) = assert(Q > 0, "cost_regular: 'Q' must be greater than zero", assert(S > 0, "cost_regular: 'S' must be greater than zero", assert(index_set_1of2(d) = 1..Q /\ index_set_2of2(d) == 1..S, "cost_regular: the transition function 'd' must be [1..Q,1..S]", assert(index_set_1of2(c) = 1..Q /\ index_set_2of2(c) == 1..S, "cost_regular: the transition cost function 'c' must be [1..Q,1..S]", assert(forall([d[i, j] in 0..Q | i in 1..Q, j in 1..S]), "cost_regular: transition function 'd' points to states outside 0..Q", % Nb: we need the parentheses around the expression otherwise the % parser thinks it's a generator call! assert((q0 in 1..Q), "cost_regular: start state 'q0' not in 1..Q", assert(F subset 1..Q, "cost_regular: final states in 'F' contain states outside 1..Q", fzn_cost_regular(x,Q,S,d,q0,F,c,C) ))))))); libminizinc-2.4.2/share/minizinc/std/count.mzn000066400000000000000000000003271360574160400214300ustar00rootroot00000000000000include "count_eq.mzn"; /** @group globals.counting Constrains \a c to be the number of occurrences of \a y in \a x. */ predicate count(array[int] of var int: x, var int: y, var int: c) = count_eq(x, y, c); libminizinc-2.4.2/share/minizinc/std/count_eq.mzn000066400000000000000000000023601360574160400221140ustar00rootroot00000000000000include "fzn_count_eq.mzn"; include "fzn_count_eq_par.mzn"; include "fzn_count_eq_reif.mzn"; include "fzn_count_eq_par_reif.mzn"; /** @group globals.counting Constrains \a c to be the number of occurrences of \a y in \a x. */ predicate count_eq(array[int] of var int: x, var int: y, var int: c) = fzn_count_eq(x,y,c); /** @group globals.counting Constrains \a c to be the number of occurrences of \a y in \a x. */ predicate count_eq(array[int] of var int: x, int: y, int: c) = fzn_count_eq_par(x,y,c); predicate count_eq(array[int] of int: x, int: y, int: c) = c=count_eq(x,y); /** @group globals.counting Returns the number of occurrences of \a y in \a x. */ function var int: count_eq(array[int] of var int: x, var int: y) ::promise_total = let { var 0..length(x): c; constraint fzn_count_eq(x,y,c); } in c; function int: count_eq(array[int] of int: x, int: y) = sum(i in index_set(x))(x[i] = y); predicate count_eq_reif(array[int] of var int: x, var int: y, var int: c, var bool: b) = fzn_count_eq_reif(x, y, c, b); predicate count_eq_reif(array[int] of var int: x, int: y, int: c, var bool: b) = fzn_count_eq_par_reif(x, y, c, b); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/count_fn.mzn000066400000000000000000000005421360574160400221120ustar00rootroot00000000000000include "count.mzn"; /** @group globals.counting Returns the number of occurrences of \a y in \a x. */ function var int: count(array[int] of var int: x, var int: y) ::promise_total = let { var 0..length(x): c::is_defined_var; constraint count(x,y,c)::defines_var(c); } in c; function int: count(array[int] of int: x, int: y) = count(i in x)(i=y); libminizinc-2.4.2/share/minizinc/std/count_geq.mzn000066400000000000000000000016101360574160400222600ustar00rootroot00000000000000include "fzn_count_geq_par.mzn"; include "fzn_count_geq.mzn"; include "fzn_count_geq_par_reif.mzn"; include "fzn_count_geq_reif.mzn"; /** @group globals.counting Constrains \a c to be greater than or equal to the number of occurrences of \a y in \a x. */ predicate count_geq(array[int] of var int: x, var int: y, var int: c) = fzn_count_geq(x,y,c); /** @group globals.counting Constrains \a c to be greater than or equal to the number of occurrences of \a y in \a x. */ predicate count_geq(array[int] of var int: x, int: y, int: c) = fzn_count_geq_par(x,y,c); predicate count_geq_reif(array[int] of var int: x, var int: y, var int: c, var bool: b) = fzn_count_geq_reif(x,y,c,b); predicate count_geq_reif(array[int] of var int: x, int: y, int: c, var bool: b) = fzn_count_geq_par_reif(x,y,c,b); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/count_gt.mzn000066400000000000000000000015661360574160400221300ustar00rootroot00000000000000include "fzn_count_gt_par.mzn"; include "fzn_count_gt.mzn"; include "fzn_count_gt_par_reif.mzn"; include "fzn_count_gt_reif.mzn"; /** @group globals.counting Constrains \a c to be strictly greater than the number of occurrences of \a y in \a x. */ predicate count_gt(array[int] of var int: x, var int: y, var int: c) = fzn_count_gt(x,y,c); /** @group globals.counting Constrains \a c to be strictly greater than the number of occurrences of \a y in \a x. */ predicate count_gt(array[int] of var int: x, int: y, int: c) = fzn_count_gt_par(x,y,c); predicate count_gt_reif(array[int] of var int: x, var int: y, var int: c, var bool: b) = fzn_count_gt_reif(x,y,c,b); predicate count_gt_reif(array[int] of var int: x, int: y, int: c, var bool: b) = fzn_count_gt_par_reif(x,y,c,b); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/count_leq.mzn000066400000000000000000000016021360574160400222660ustar00rootroot00000000000000include "fzn_count_leq_par.mzn"; include "fzn_count_leq.mzn"; include "fzn_count_leq_par_reif.mzn"; include "fzn_count_leq_reif.mzn"; /** @group globals.counting Constrains \a c to be less than or equal to the number of occurrences of \a y in \a x. */ predicate count_leq(array[int] of var int: x, var int: y, var int: c) = fzn_count_leq(x,y,c); /** @group globals.counting Constrains \a c to be less than or equal to the number of occurrences of \a y in \a x. */ predicate count_leq(array[int] of var int: x, int: y, int: c) = fzn_count_leq_par(x,y,c); predicate count_leq_reif(array[int] of var int: x, var int: y, var int: c, var bool: b) = fzn_count_leq_reif(x,y,c,b); predicate count_leq_reif(array[int] of var int: x, int: y, int: c, var bool: b) = fzn_count_leq_par_reif(x,y,c,b); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/count_lt.mzn000066400000000000000000000015601360574160400221270ustar00rootroot00000000000000include "fzn_count_lt.mzn"; include "fzn_count_lt_par.mzn"; include "fzn_count_lt_reif.mzn"; include "fzn_count_lt_par_reif.mzn"; /** @group globals.counting Constrains \a c to be strictly less than the number of occurrences of \a y in \a x. */ predicate count_lt(array[int] of var int: x, var int: y, var int: c) = fzn_count_lt(x,y,c); /** @group globals.counting Constrains \a c to be strictly less than the number of occurrences of \a y in \a x. */ predicate count_lt(array[int] of var int: x, int: y, int: c) = fzn_count_lt_par(x,y,c); predicate count_lt_reif(array[int] of var int: x, var int: y, var int: c, var bool: b) = fzn_count_lt_reif(x,y,c,b); predicate count_lt_reif(array[int] of var int: x, int: y, int: c, var bool: b) = fzn_count_lt_par_reif(x,y,c,b); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/count_neq.mzn000066400000000000000000000015601360574160400222730ustar00rootroot00000000000000include "fzn_count_neq_par.mzn"; include "fzn_count_neq.mzn"; include "fzn_count_neq_par_reif.mzn"; include "fzn_count_neq_reif.mzn"; /** @group globals.counting Constrains \a c to be not equal to the number of occurrences of \a y in \a x. */ predicate count_neq(array[int] of var int: x, var int: y, var int: c) = fzn_count_neq(x,y,c); /** @group globals.counting Constrains \a c to be not equal to the number of occurrences of \a y in \a x. */ predicate count_neq(array[int] of var int: x, int: y, int: c) = fzn_count_neq_par(x,y,c); predicate count_neq_reif(array[int] of var int: x, var int: y, var int: c, var bool: b) = fzn_count_neq_reif(x,y,c,b); predicate count_neq_reif(array[int] of var int: x, int: y, int: c, var bool: b) = fzn_count_neq_par_reif(x,y,c,b); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/cumulative.mzn000066400000000000000000000022541360574160400224570ustar00rootroot00000000000000include "all_different.mzn"; include "disjunctive.mzn"; include "fzn_cumulative.mzn"; include "fzn_cumulative_reif.mzn"; /** @group globals.scheduling Requires that a set of tasks given by start times \a s, durations \a d, and resource requirements \a r, never require more than a global resource bound \a b at any one time. Assumptions: - forall \p i, \a d[\p i] >= 0 and \a r[\p i] >= 0 */ predicate cumulative(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = assert(index_set(s) == index_set(d) /\ index_set(s) == index_set(r), "cumulative: the 3 array arguments must have identical index sets", assert(lb_array(d) >= 0 /\ lb_array(r) >= 0, "cumulative: durations and resource usages must be non-negative", if is_fixed(b) /\ forall(i in index_set(r)) (is_fixed(r[i]) /\ fix(r[i]) + lb_array(r) > ub(b)) then if forall(i in index_set(d))(is_fixed(d[i]) /\ fix(d[i]) == 1) then all_different(s) else disjunctive(s, d) endif else fzn_cumulative(s, d, r, b) endif )); libminizinc-2.4.2/share/minizinc/std/cumulative_opt.mzn000066400000000000000000000016531360574160400233430ustar00rootroot00000000000000include "fzn_cumulative_opt.mzn"; include "fzn_cumulative_opt_reif.mzn"; /** @group globals.scheduling Requires that a set of tasks given by start times \a s, durations \a d, and resource requirements \a r, never require more than a global resource bound \a b at any one time. Start times are optional variables, so that absent tasks do not need to be scheduled. Assumptions: - forall \p i, \a d[\p i] >= 0 and \a r[\p i] >= 0 */ predicate cumulative(array[int] of var opt int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = assert(index_set(s) == index_set(d) /\ index_set(s) == index_set(r), "cumulative: the 3 array arguments must have identical index sets", assert(lb_array(d) >= 0 /\ lb_array(r) >= 0, "cumulative: durations and resource usages must be non-negative", fzn_cumulative_opt(s,d,r,b) ) ); libminizinc-2.4.2/share/minizinc/std/dag.mzn000066400000000000000000000017171360574160400210370ustar00rootroot00000000000000include "fzn_dag.mzn"; include "fzn_dag_reif.mzn"; /** @group globals.graph Constrains the subgraph \a ns and \a es of a given directed graph to be a DAG. @param from: the leaving node for each edge @param to: the entering node for each edge @param ns: a Boolean for each node whether it is in the subgraph @param es: a Boolean for each edge whether it is in the subgraph */ predicate dag(array[int] of $$N: from, array[int] of $$N: to, array[$$N] of var bool: ns, array[int] of var bool: es) = assert(index_set(from) = index_set(to),"dreachable: index set of from and to must be identical") /\ assert(index_set(from) = index_set(es),"dreachable: index set of from and es must be identical") /\ assert(dom_array(from) subset index_set(ns),"dreachable: nodes in from must be in index set of ns") /\ assert(dom_array(from) subset index_set(ns),"dreachable: nodes in to must be in index set of ns") /\ fzn_dag(from,to,ns,es); libminizinc-2.4.2/share/minizinc/std/decreasing.mzn000066400000000000000000000015201360574160400224000ustar00rootroot00000000000000include "decreasing_bool.mzn"; include "decreasing_float.mzn"; include "decreasing_int.mzn"; include "decreasing_set.mzn"; /** @group globals.sort Requires that the array \a x is in decreasing order (duplicates are allowed). */ predicate decreasing(array[int] of var bool: x) = decreasing_bool(x); /** @group globals.sort Requires that the array \a x is in decreasing order (duplicates are allowed). */ predicate decreasing(array[int] of var float: x) = decreasing_float(x); /** @group globals.sort Requires that the array \a x is in decreasing order (duplicates are allowed). */ predicate decreasing(array[int] of var int: x) = decreasing_int(x); /** @group globals.sort Requires that the array \a x is in decreasing order (duplicates are allowed). */ predicate decreasing(array[int] of var set of int: x) = decreasing_set(x); libminizinc-2.4.2/share/minizinc/std/decreasing_bool.mzn000066400000000000000000000006171360574160400234210ustar00rootroot00000000000000include "fzn_decreasing_bool.mzn"; include "fzn_decreasing_bool_reif.mzn"; %-----------------------------------------------------------------------------% % Requires that the array 'x' is in decreasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate decreasing_bool(array[int] of var bool: x) = fzn_decreasing_bool(x); libminizinc-2.4.2/share/minizinc/std/decreasing_float.mzn000066400000000000000000000005521360574160400235710ustar00rootroot00000000000000include "fzn_decreasing_float.mzn"; %-----------------------------------------------------------------------------% % Requires that the array 'x' is in decreasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate decreasing_float(array[int] of var float: x) = fzn_decreasing_float(x); libminizinc-2.4.2/share/minizinc/std/decreasing_int.mzn000066400000000000000000000005451360574160400232600ustar00rootroot00000000000000include "fzn_decreasing_int.mzn"; %-----------------------------------------------------------------------------% % Requires that the array 'x' is in decreasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate decreasing_int(array[int] of var int: x) = fzn_decreasing_int(x); libminizinc-2.4.2/share/minizinc/std/decreasing_set.mzn000066400000000000000000000005531360574160400232600ustar00rootroot00000000000000include "fzn_decreasing_set.mzn"; %-----------------------------------------------------------------------------% % Requires that the array 'x' is in decreasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate decreasing_set(array[int] of var set of int: x) = fzn_decreasing_set(x); libminizinc-2.4.2/share/minizinc/std/diffn.mzn000066400000000000000000000013631360574160400213670ustar00rootroot00000000000000include "fzn_diffn.mzn"; include "fzn_diffn_reif.mzn"; /** @group globals.packing Constrains rectangles \p i, given by their origins (\a x[\p i], \a y[\p i]) and sizes (\a dx[\p i], \a dy[\p i]), to be non-overlapping. Zero-width rectangles can still not overlap with any other rectangle. */ predicate diffn(array[int] of var int: x, array[int] of var int: y, array[int] of var int: dx, array[int] of var int: dy) = assert( index_set(x) = index_set(y) /\ index_set(x) = index_set(dx) /\ index_set(x) = index_set(dy), "diffn: index set mismatch", fzn_diffn(x,y,dx,dy) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/diffn_k.mzn000066400000000000000000000014421360574160400216770ustar00rootroot00000000000000include "fzn_diffn_k.mzn"; include "fzn_diffn_k_reif.mzn"; /** @group globals.packing Constrains \p k-dimensional boxes to be non-overlapping. For each box \p i and dimension \p j, \a box_posn[\p i, \p j] is the base position of the box in dimension \p j, and \a box_size[\p i, \p j] is the size in that dimension. Boxes whose size is 0 in any dimension still cannot overlap with any other box. */ predicate diffn_k(array[int,int] of var int: box_posn, array[int,int] of var int: box_size) = let { set of int: DIMS= index_set_2of2(box_posn) } in assert(index_set_2of2(box_size) = DIMS /\ index_set_1of2(box_posn) = index_set_1of2(box_size), "diffn: index sets of arguments are incorrect", fzn_diffn_k(box_posn, box_size) ); libminizinc-2.4.2/share/minizinc/std/diffn_nonstrict.mzn000066400000000000000000000013201360574160400234630ustar00rootroot00000000000000include "fzn_diffn_nonstrict.mzn"; include "fzn_diffn_nonstrict_reif.mzn"; /** @group globals.packing Constrains rectangles \p i, given by their origins (\a x[\p i], \a y[\p i]) and sizes (\a dx[\p i], \a dy[\p i]), to be non-overlapping. Zero-width rectangles can be packed anywhere. */ predicate diffn_nonstrict(array[int] of var int: x, array[int] of var int: y, array[int] of var int: dx, array[int] of var int: dy) = assert( index_set(x) = index_set(y) /\ index_set(x) = index_set(dx) /\ index_set(x) = index_set(dy), "diffn: index set mismatch", fzn_diffn_nonstrict(x,y,dx,dy) ); libminizinc-2.4.2/share/minizinc/std/diffn_nonstrict_k.mzn000066400000000000000000000015051360574160400240020ustar00rootroot00000000000000include "fzn_diffn_nonstrict_k.mzn"; include "fzn_diffn_nonstrict_k_reif.mzn"; /** @group globals.packing Constrains \p k-dimensional boxes to be non-overlapping. For each box \p i and dimension \p j, \a box_posn[\p i, \p j] is the base position of the box in dimension \p j, and \a box_size[\p i, \p j] is the size in that dimension. Boxes whose size is 0 in at least one dimension can be packed anywhere. */ predicate diffn_nonstrict_k(array[int,int] of var int: box_posn, array[int,int] of var int: box_size) = let { set of int: DIMS= index_set_2of2(box_posn) } in assert(index_set_2of2(box_size) = DIMS /\ index_set_1of2(box_posn) = index_set_1of2(box_size), "diffn: index sets of arguments are incorrect", fzn_diffn_nonstrict_k(box_posn, box_size) ) libminizinc-2.4.2/share/minizinc/std/disjoint.mzn000066400000000000000000000003371360574160400221240ustar00rootroot00000000000000include "fzn_disjoint.mzn"; include "fzn_disjoint_reif.mzn"; /** @group globals Requires that sets \a s1 and \a s2 do not intersect. */ predicate disjoint(var set of int: s1, var set of int: s2) = fzn_disjoint(s1,s2); libminizinc-2.4.2/share/minizinc/std/disjunctive.mzn000066400000000000000000000013231360574160400226240ustar00rootroot00000000000000include "disjunctive_strict.mzn"; include "fzn_disjunctive.mzn"; include "fzn_disjunctive_reif.mzn"; /** @group globals.scheduling Requires that a set of tasks given by start times \a s and durations \a d do not overlap in time. Tasks with duration 0 can be scheduled at any time, even in the middle of other tasks. Assumptions: - forall \p i, \a d[\p i] >= 0 */ predicate disjunctive(array[int] of var int: s, array[int] of var int: d) = assert(index_set(s) == index_set(d), "disjunctive: the array arguments must have identical index sets", if (lb_array(d) > 0) then disjunctive_strict(s,d) else fzn_disjunctive(s,d) endif ); libminizinc-2.4.2/share/minizinc/std/disjunctive_opt.mzn000066400000000000000000000015621360574160400235130ustar00rootroot00000000000000include "disjunctive_strict_opt.mzn"; include "fzn_disjunctive_opt.mzn"; include "fzn_disjunctive_opt_reif.mzn"; /** @group globals.scheduling Requires that a set of tasks given by start times \a s and durations \a d do not overlap in time. Tasks with duration 0 can be scheduled at any time, even in the middle of other tasks. Start times are optional variables, so that absent tasks do not need to be scheduled. Assumptions: - forall \p i, \a d[\p i] >= 0 */ predicate disjunctive(array[int] of var opt int: s, array[int] of var int: d) = assert(index_set(s) == index_set(d), "disjunctive: the array arguments must have identical index sets", forall (i in index_set(d)) (d[i] >= 0) /\ if (lb_array(d) > 0) then disjunctive_strict(s,d) else fzn_disjunctive_opt(s, d) endif ); libminizinc-2.4.2/share/minizinc/std/disjunctive_strict.mzn000066400000000000000000000011741360574160400242200ustar00rootroot00000000000000include "fzn_disjunctive_strict.mzn"; include "fzn_disjunctive_strict_reif.mzn"; /** @group globals.scheduling Requires that a set of tasks given by start times \a s and durations \a d do not overlap in time. Tasks with duration 0 CANNOT be scheduled at any time, but only when no other task is running. Assumptions: - forall \p i, \a d[\p i] >= 0 */ predicate disjunctive_strict(array[int] of var int: s, array[int] of var int: d) = assert(index_set(s) == index_set(d), "disjunctive: the array arguments must have identical index sets", fzn_disjunctive_strict(s,d) ); libminizinc-2.4.2/share/minizinc/std/disjunctive_strict_opt.mzn000066400000000000000000000013431360574160400251000ustar00rootroot00000000000000include "fzn_disjunctive_strict_opt.mzn"; include "fzn_disjunctive_strict_opt_reif.mzn"; /** @group globals.scheduling Requires that a set of tasks given by start times \a s and durations \a d do not overlap in time. Tasks with duration 0 CANNOT be scheduled at any time, but only when no other task is running. Start times are optional variables, so that absent tasks do not need to be scheduled. Assumptions: - forall \p i, \a d[\p i] >= 0 */ predicate disjunctive_strict(array[int] of var opt int: s, array[int] of var int: d) = assert(index_set(s) == index_set(d), "disjunctive: the array arguments must have identical index sets", fzn_disjunctive_strict_opt(s,d) ); libminizinc-2.4.2/share/minizinc/std/distribute.mzn000066400000000000000000000010561360574160400224560ustar00rootroot00000000000000include "fzn_distribute.mzn"; include "fzn_distribute_reif.mzn"; /** @group globals.counting Requires that \a card[\p i] is the number of occurences of \a value[\p i] in \a base. The values in \a value need not be distinct. */ predicate distribute(array[int] of var int: card, array[int] of var int: value, array[int] of var int: base) = assert(index_set(card) == index_set(value), "distribute: card and value arrays must have identical index sets", fzn_distribute(card, value, base) ); libminizinc-2.4.2/share/minizinc/std/distribute_fn.mzn000066400000000000000000000007301360574160400231370ustar00rootroot00000000000000include "distribute.mzn"; /** @group globals.counting Returns an array of the number of occurences of \a value[\p i] in \a base. The values in \a value need not be distinct. */ function array[int] of var int: distribute(array[int] of var int: value, array[int] of var int: base) :: promise_total = let { array[index_set(value)] of var 0..length(base): card; constraint distribute(card, value, base); } in card; libminizinc-2.4.2/share/minizinc/std/element.mzn000066400000000000000000000013661360574160400217350ustar00rootroot00000000000000include "element_bool.mzn"; include "element_float.mzn"; include "element_int.mzn"; include "element_set.mzn"; %-----------------------------------------------------------------------------% % Requires that 'y' is the ith element of the array 'x'. %-----------------------------------------------------------------------------% predicate element(var int: i, array[int] of var bool: x, var bool: y) = element_bool(i, x, y); predicate element(var int: i, array[int] of var float: x, var float: y) = element_float(i, x, y); predicate element(var int: i, array[int] of var int: x, var int: y) = element_int(i, x, y); predicate element(var int: i, array[int] of var set of int: x, var set of int: y) = element_set(i, x, y); libminizinc-2.4.2/share/minizinc/std/element_bool.mzn000066400000000000000000000004651360574160400227470ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that 'y' is the ith element of the array 'x'. %-----------------------------------------------------------------------------% predicate element_bool(var int: i, array[int] of var bool: x, var bool: y) = y = x[i]; libminizinc-2.4.2/share/minizinc/std/element_float.mzn000066400000000000000000000004671360574160400231230ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that 'y' is the ith element of the array 'x'. %-----------------------------------------------------------------------------% predicate element_float(var int: i, array[int] of var float: x, var float: y) = y = x[i];libminizinc-2.4.2/share/minizinc/std/element_int.mzn000066400000000000000000000004621360574160400226030ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that 'y' is the ith element of the array 'x'. %-----------------------------------------------------------------------------% predicate element_int(var int: i, array[int] of var int: x, var int: y) = y = x[i]; libminizinc-2.4.2/share/minizinc/std/element_set.mzn000066400000000000000000000005261360574160400226050ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that 'y' is the ith element of the array 'x'. %-----------------------------------------------------------------------------% predicate element_set(var int: i, array[int] of var set of int: x, var set of int: y) = y = x[i]; libminizinc-2.4.2/share/minizinc/std/exactly.mzn000066400000000000000000000010011360574160400217370ustar00rootroot00000000000000include "exactly_int.mzn"; include "exactly_set.mzn"; /** @group globals.deprecated Requires exactly \a n variables in \a x to take the value \a v. This constraint is deprecated. Use count(i in x)(i=v) = n instead. */ predicate exactly(int: n, array[int] of var int: x, int: v) = exactly_int(n, x, v); /** @group globals.counting Requires exactly \a n variables in \a x to take the value \a v. */ predicate exactly(int: n, array[int] of var set of int: x, set of int: v) = exactly_set(n, x, v); libminizinc-2.4.2/share/minizinc/std/exactly.mzn.deprecated.mzn000066400000000000000000000002331360574160400246470ustar00rootroot00000000000000predicate exactly(int: n, array[int] of var int: x, int: v) ::mzn_deprecated("2.4.0","https://www.minizinc.org/doc-2.4.0/en/lib-globals.html#deprecated"); libminizinc-2.4.2/share/minizinc/std/exactly_int.mzn000066400000000000000000000006041360574160400226210ustar00rootroot00000000000000include "fzn_exactly_int.mzn"; include "fzn_exactly_int_reif.mzn"; %-----------------------------------------------------------------------------% % Requires exactly 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate exactly_int(int: n, array[int] of var int: x, int: v) = fzn_exactly_int(n, x, v); libminizinc-2.4.2/share/minizinc/std/exactly_set.mzn000066400000000000000000000006221360574160400226220ustar00rootroot00000000000000include "fzn_exactly_set.mzn"; include "fzn_exactly_set_reif.mzn"; %-----------------------------------------------------------------------------% % Requires exactly 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate exactly_set(int: n, array[int] of var set of int: x, set of int: v) = fzn_exactly_set(n, x, v); libminizinc-2.4.2/share/minizinc/std/flatzinc_builtins.mzn000066400000000000000000000404541360574160400240300ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % % FlatZinc builtins % % This section contains declarations for the standard FlatZinc builtins. % They can be redefined by providing a custom redefinitions.mzn in the % solver globals library. % /*** @groupdef flatzinc FlatZinc builtins These are the standard constraints that need to be supported by FlatZinc solvers (or redefined in the redefinitions.mzn file). */ /*** @groupdef flatzinc.int Integer FlatZinc builtins */ /** @group flatzinc.int Constrains \a b to be the absolute value of \a a */ predicate int_abs(var int: a, var int: b); /** @group flatzinc.int Constrains \a a to be equal to \a b */ predicate int_eq(var int: a, var int: b); /** @group flatzinc.int Constrains (\a a=\a b) \( \leftrightarrow \) \a r */ predicate int_eq_reif(var int: a, var int: b, var bool: r); /** @group flatzinc.int Constrains \a a to be less than or equal to \a b */ predicate int_le(var int: a, var int: b); /** @group flatzinc.int Constrains (\a a ≤ \a b) \( \leftrightarrow \) \a r */ predicate int_le_reif(var int: a, var int: b, var bool: r); /** @group flatzinc.int Constrains \( \a c = \sum_i \a as[i]*\a bs[i] \) */ predicate int_lin_eq(array[int] of int: as, array[int] of var int: bs, int: c); /** @group flatzinc.int Constrains \( \a r \leftrightarrow (\a c = \sum_i \a as[i]*\a bs[i]) \) */ predicate int_lin_eq_reif(array[int] of int: as, array[int] of var int: bs,int: c, var bool: r); /** @group flatzinc.int Constrains \( \a c \neq \sum_i \a as[i]*\a bs[i] \) */ predicate int_lin_ne(array[int] of int: as, array[int] of var int: bs, int: c); /** @group flatzinc.int Constrains \( \a r \leftrightarrow (\a c \neq \sum_i \a as[i]*\a bs[i]) \) */ predicate int_lin_ne_reif(array[int] of int: as, array[int] of var int: bs,int: c, var bool: r); /** @group flatzinc.int Constrains \( \sum \) \a as[\p i]*\a bs[\p i] ≤ \a c */ predicate int_lin_le(array[int] of int: as, array[int] of var int: bs, int: c); /** @group flatzinc.int Constrains \a r \( \leftrightarrow \) (\( \sum \) \a as[\p i]*\a bs[\p i] ≤ \a c) */ predicate int_lin_le_reif(array[int] of int: as, array[int] of var int: bs,int: c, var bool: r); /** @group flatzinc.int Constrains \a a ≠ \a b */ predicate int_ne(var int: a, var int: b); /** @group flatzinc.int \a r \( \leftrightarrow \) (\a a ≠ \a b) */ predicate int_ne_reif(var int: a, var int: b, var bool: r); /** @group flatzinc.int Constrains \a a + \a b = \a c */ predicate int_plus(var int: a, var int: b, var int: c); /** @group flatzinc.int Constrains \a a / \a b = \a c */ predicate int_div(var int: a, var int: b, var int: c); /** @group flatzinc.int Constrains \a a < \a b */ predicate int_lt(var int: a, var int: b); /** @group flatzinc.int Constrains \a r \( \leftrightarrow \) (\a a < \a b) */ predicate int_lt_reif(var int: a, var int: b, var bool: r); /** @group flatzinc.int Constrains max(\a a, \a b) = \a c */ predicate int_max(var int: a, var int: b, var int: c); /** @group flatzinc.int Constrains min(\a a, \a b) = \a c */ predicate int_min(var int: a, var int: b, var int: c); /** @group flatzinc.int Constrains \a a % \a b = \a c */ predicate int_mod(var int: a, var int: b, var int: c); /** @group flatzinc.int Constrains \a a * \a b = \a c */ predicate int_times(var int: a, var int: b, var int: c); /** @group flatzinc.int Constrains \a z = \(\a x ^ {\a y}\) */ predicate int_pow(var int: x, var int: y, var int: z); /*** @groupdef flatzinc.bool Bool FlatZinc builtins */ /** @group flatzinc.bool Constrains \( \a b \in \{0,1\} \) and \( \a a \leftrightarrow \a b=1 \) */ predicate bool2int(var bool: a, var int: b); /** @group flatzinc.bool Constrains \( \a r \leftrightarrow \a a \land \a b \) */ predicate bool_and(var bool: a, var bool: b, var bool: r); /** @group flatzinc.bool Constrains \( \bigvee_i \a as[i] \lor \bigvee_j \lnot \a bs[j] \) */ predicate bool_clause(array[int] of var bool: as, array[int] of var bool: bs); /** @group flatzinc.bool Constrains \a a = \a b */ predicate bool_eq(var bool: a, var bool: b); /** @group flatzinc.bool Constrains \a r \( \leftrightarrow \) (\a a = \a b) */ predicate bool_eq_reif(var bool: a, var bool: b, var bool: r); /** @group flatzinc.bool Constrains \a a ≤ \a b */ predicate bool_le(var bool: a, var bool: b); /** @group flatzinc.bool Constrains \a r \( \leftrightarrow \) (\a a ≤ \a b) */ predicate bool_le_reif(var bool: a, var bool: b, var bool: r); /** @group flatzinc.bool Constrains \( \a c = \sum_i \a as[i]*\a bs[i] \) */ predicate bool_lin_eq(array[int] of int: as, array[int] of var bool: bs, var int: c); /** @group flatzinc.bool Constrains \( \a c \leq \sum_i \a as[i]*\a bs[i] \) */ predicate bool_lin_le(array[int] of int: as, array[int] of var bool: bs, int: c); /** @group flatzinc.bool Constrains \a a < \a b */ predicate bool_lt(var bool: a, var bool: b); /** @group flatzinc.bool Constrains \a r \( \leftrightarrow \) (\a a < \a b) */ predicate bool_lt_reif(var bool: a, var bool: b, var bool: r); /** @group flatzinc.bool Constrains \a a ≠ \a b */ predicate bool_not(var bool: a, var bool: b); /** @group flatzinc.bool Constrains \( \a r \leftrightarrow \a a \lor \a b \) */ predicate bool_or(var bool: a, var bool: b, var bool: r); /** @group flatzinc.bool Constrains \( \a r \leftrightarrow \a a \oplus \a b \) */ predicate bool_xor(var bool: a, var bool: b, var bool: r); /** @group flatzinc.bool Constrains \a a \( \oplus \) \a b */ predicate bool_xor(var bool: a, var bool: b); /*** @groupdef flatzinc.set Set FlatZinc builtins */ /** @group flatzinc.set Constrains \a x \( \in \) \a S */ predicate set_in(var int: x, set of int: S); /** @group flatzinc.set Constrains \a x \( \in \) \a S */ predicate set_in(var int: x, var set of int: S); /** @group flatzinc.set Constrains \a x = |\a S| */ predicate set_card(var set of int: S, var int: x); /** @group flatzinc.set Constrains \( \a r \leftrightarrow (\a x \in \a S) \) */ predicate set_in_reif(var int: x, set of int: S, var bool: r); /** @group flatzinc.set Constrains \( \a r \leftrightarrow (\a x \in \a S) \) */ predicate set_in_reif(var int: x, var set of int: S, var bool: r); /** @group flatzinc.set Constrains \a x \( \subseteq \) \a y */ predicate set_subset(var set of int: x, var set of int: y); /** @group flatzinc.set Constrains \a x \( \supseteq \) \a y */ predicate set_superset(var set of int: x, var set of int: y); /** @group flatzinc.set Constrains \( \a r \leftrightarrow (\a x \subseteq \a y) \) */ predicate set_subset_reif(var set of int: x, var set of int: y, var bool: r); /** @group flatzinc.set Constrains \a x ≤ \a y (lexicographic order of the sorted lists of elements) */ predicate set_le(var set of int: x, var set of int: y); /** @group flatzinc.set Constrains \( \a r \leftrightarrow (\a x \leq \a y) \) (lexicographic order of the sorted lists of elements) */ predicate set_le_reif(var set of int: x, var set of int: y, var bool: r); /** @group flatzinc.set Constrains \a x < \a y (lexicographic order of the sorted lists of elements) */ predicate set_lt(var set of int: x, var set of int: y); /** @group flatzinc.set Constrains \( \a r \leftrightarrow (\a x < \a y) \) (lexicographic order of the sorted lists of elements) */ predicate set_lt_reif(var set of int: x, var set of int: y, var bool: r); /** @group flatzinc.set Constrains \a x = \a y */ predicate set_eq(var set of int: x, var set of int: y); /** @group flatzinc.set Constrains \a r \( \leftrightarrow \) (\a x = \a y) */ predicate set_eq_reif(var set of int: x, var set of int: y, var bool: r); /** @group flatzinc.set Constrains \a x ≠ \a y */ predicate set_ne(var set of int: x, var set of int: y); /** @group flatzinc.set Constrains \a r \( \leftrightarrow \) (\a x ≠ \a y) */ predicate set_ne_reif(var set of int: x, var set of int: y, var bool: r); /** @group flatzinc.set Constrains \a r = \a x \( \cap \) \a y */ predicate set_intersect(var set of int: x, var set of int: y, var set of int: r); /** @group flatzinc.set Constrains \a r = \a x \( \cup \) \a y */ predicate set_union(var set of int: x, var set of int: y, var set of int: r); /** @group flatzinc.set Constrains \a r = \a x \( \setminus \) \a y */ predicate set_diff(var set of int: x, var set of int: y, var set of int: r); /** @group flatzinc.set Constrains \a r to be the symmetric difference of \a x and \a y */ predicate set_symdiff(var set of int: x, var set of int: y, var set of int: r); /*** @groupdef flatzinc.float Float FlatZinc builtins */ /** @group flatzinc.float Constrains \a b to be the absolute value of \a a */ predicate float_abs(var float: a, var float: b); /** @group flatzinc.float Constrains \a b = acos(\a a) */ predicate float_acos(var float: a, var float: b); /** @group flatzinc.float Constrains \a b = acosh(\a a) */ predicate float_acosh(var float: a, var float: b); /** @group flatzinc.float Constrains \a b = asin(\a a) */ predicate float_asin(var float: a, var float: b); /** @group flatzinc.float Constrains \a b = asinh(\a a) */ predicate float_asinh(var float: a, var float: b); /** @group flatzinc.float Constrains \a b = atan(\a a) */ predicate float_atan(var float: a, var float: b); /** @group flatzinc.float Constrains \a b = atanh(\a a) */ predicate float_atanh(var float: a, var float: b); /** @group flatzinc.float Constrains \a b = cos(\a a) */ predicate float_cos(var float: a, var float: b); /** @group flatzinc.float Constrains \a b = cosh(\a a) */ predicate float_cosh(var float: a, var float: b); /** @group flatzinc.float Constrains \a b = exp(\a a) */ predicate float_exp(var float: a, var float: b); /** @group flatzinc.float Constrains \a b = ln(\a a) */ predicate float_ln(var float: a, var float: b); /** @group flatzinc.float Constrains \a b = log10(\a a) */ predicate float_log10(var float: a, var float: b); /** @group flatzinc.float Constrains \a b = log2(\a a) */ predicate float_log2(var float: a, var float: b); /** @group flatzinc.float Constrains \(\a b = \sqrt{\a a}\) */ predicate float_sqrt(var float: a, var float: b); /** @group flatzinc.float Constrains \a z = \(\a x ^ {\a y}\) */ predicate float_pow(var float: x, var float: y, var float: z); /** @group flatzinc.float Constrains \a b = sin(\a a) */ predicate float_sin(var float: a, var float: b); /** @group flatzinc.float Constrains \a b = sinh(\a a) */ predicate float_sinh(var float: a, var float: b); /** @group flatzinc.float Constrains \a b = tan(\a a) */ predicate float_tan(var float: a, var float: b); /** @group flatzinc.float Constrains \a b = tanh(\a a) */ predicate float_tanh(var float: a, var float: b); /** @group flatzinc.float Constrains \a a = \a b */ predicate float_eq(var float: a, var float: b); /** @group flatzinc.float Constrains \a r \( \leftrightarrow \) (\a a = \a b) */ predicate float_eq_reif(var float: a, var float: b, var bool: r); /** @group flatzinc.float Constrains \a a ≤ \a b */ predicate float_le(var float: a, var float: b); /** @group flatzinc.float Constrains \a r \( \leftrightarrow \) (\a a ≤ \a b) */ predicate float_le_reif(var float: a, var float: b, var bool: r); /** @group flatzinc.float Constrains \a a < \a b */ predicate float_lt(var float: a, var float: b); /** @group flatzinc.float Constrains \a r \( \leftrightarrow \) (\a a < \a b) */ predicate float_lt_reif(var float: a, var float: b, var bool: r); /** @group flatzinc.float Constrains \a a ≠ \a b */ predicate float_ne(var float: a, var float: b); /** @group flatzinc.float Constrains \a r \( \leftrightarrow \) (\a a ≠ \a b) */ predicate float_ne_reif(var float: a, var float: b, var bool: r); /** @group flatzinc.float Constrains \( \a a \in\ [ \a b, \a c ] \) */ predicate float_in(var float: a, float: b, float: c); /** @group flatzinc.float Constrains \a r \( \leftrightarrow \) \( \a a \in\ [ \a b, \a c ] \) */ predicate float_in_reif(var float: a, float: b, float: c, var bool: r); /** @group flatzinc.float Constrains the domain of \a x using the values in \a as, using each pair of values \a as[2*\p i-1]..\a as[2*\p i] for \p i in 1..\p n/2 as a possible range */ predicate float_dom(var float: x, array[int] of float: as); /** @group flatzinc.float Constrains \( \a c = \sum_i \a as[i]*\a bs[i] \) */ predicate float_lin_eq(array[int] of float: as, array[int] of var float: bs, float: c); /** @group flatzinc.float Constrains \( \a r \leftrightarrow (\a c = \sum_i \a as[i]*\a bs[i]) \) */ predicate float_lin_eq_reif(array[int] of float: as, array[int] of var float: bs, float: c, var bool: r); /** @group flatzinc.float Constrains \( \a c \leq \sum_i \a as[i]*\a bs[i] \) */ predicate float_lin_le(array[int] of float: as, array[int] of var float: bs, float: c); /** @group flatzinc.float Constrains \( \a r \leftrightarrow (\a c \leq \sum_i \a as[i]*\a bs[i]) \) */ predicate float_lin_le_reif(array[int] of float: as, array[int] of var float: bs, float: c, var bool: r); /** @group flatzinc.float Constrains \( \a c < \sum_i \a as[i]*\a bs[i] \) */ predicate float_lin_lt(array[int] of float: as, array[int] of var float: bs, float: c); /** @group flatzinc.float Constrains \( \a r \leftrightarrow (\a c < \sum_i \a as[i]*\a bs[i]) \) */ predicate float_lin_lt_reif(array[int] of float: as, array[int] of var float: bs, float: c, var bool: r); /** @group flatzinc.float Constrains \( \a c \neq \sum_i \a as[i]*\a bs[i] \) */ predicate float_lin_ne(array[int] of float: as, array[int] of var float: bs, float: c); /** @group flatzinc.float Constrains \( \a r \leftrightarrow (\a c \neq \sum_i \a as[i]*\a bs[i]) \) */ predicate float_lin_ne_reif(array[int] of float: as, array[int] of var float: bs, float: c, var bool: r); /** @group flatzinc.float Constrains max(\a a, \a b) = \a c */ predicate float_max(var float: a, var float: b, var float: c); /** @group flatzinc.float Constrains min(\a a, \a b) = \a c */ predicate float_min(var float: a, var float: b, var float: c); /** @group flatzinc.float Constrains \a a + \a b = \a c */ predicate float_plus(var float: a, var float: b, var float: c); /** @group flatzinc.float Constrains \a a / \a b = \a c */ predicate float_div(var float: a, var float: b, var float: c); /** @group flatzinc.float Constrains \a a * \a b = \a c */ predicate float_times(var float: a, var float: b, var float: c); /** @group flatzinc.float Constrains \a y=\a x */ predicate int2float(var int: x, var float: y); % Array constraints /** @group flatzinc.bool Constrains \( \a r \leftrightarrow \bigwedge_i \a as[i]\) */ predicate array_bool_and(array[int] of var bool: as, var bool: r); /** @group flatzinc.bool Constrains \( \a r \leftrightarrow \bigvee_i \a as[i]\) */ predicate array_bool_or(array[int] of var bool: as, var bool: r); /** @group flatzinc.bool Constrains \( \oplus_i\ \a as[i]\) */ predicate array_bool_xor(array[int] of var bool: as); /** @group flatzinc.bool Constrains \a as[\a b] = \a c */ predicate array_bool_element(var int: b, array[int] of bool: as, var bool: c); /** @group flatzinc.int Constrains \a as[\a b] = \a c */ predicate array_int_element(var int: b, array[int] of int: as, var int: c); /** @group flatzinc.float Constrains \a as[\a b] = \a c */ predicate array_float_element(var int: b, array[int] of float: as, var float: c); /** @group flatzinc.set Constrains \a as[\a b] = \a c */ predicate array_set_element(var int: b, array[int] of set of int: as, var set of int: c); /** @group flatzinc.bool Constrains \a as[\a b] = \a c */ predicate array_var_bool_element(var int: b, array[int] of var bool: as, var bool: c); /** @group flatzinc.int Constrains \a as[\a b] = \a c */ predicate array_var_int_element(var int: b, array[int] of var int: as, var int: c); /** @group flatzinc.float Constrains \a as[\a b] = \a c */ predicate array_var_float_element(var int: b, array[int] of var float: as, var float: c); /** @group flatzinc.set Constrains \a as[\a b] = \a c */ predicate array_var_set_element(var int: b, array[int] of var set of int: as, var set of int: c); /** @group flatzinc.int Constrains \a m to be the maximum value of the (non-empty) array \a x */ predicate array_int_maximum(var int: m, array[int] of var int: x); /** @group flatzinc.float Constrains \a m to be the maximum value of the (non-empty) array \a x */ predicate array_float_maximum(var int: m, array[int] of var int: x); /** @group flatzinc.int Constrains \a m to be the minimum value of the (non-empty) array \a x */ predicate array_int_minimum(var int: m, array[int] of var int: x); /** @group flatzinc.float Constrains \a m to be the minimum value of the (non-empty) array \a x */ predicate array_float_minimum(var int: m, array[int] of var int: x); libminizinc-2.4.2/share/minizinc/std/fzn_all_different_int.mzn000066400000000000000000000005261360574160400246260ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Constrains the array of objects 'x' to be all different. %-----------------------------------------------------------------------------% predicate fzn_all_different_int(array[int] of var int: x) = forall(i,j in index_set(x) where i < j) ( x[i] != x[j] ); libminizinc-2.4.2/share/minizinc/std/fzn_all_different_int_reif.mzn000066400000000000000000000005561360574160400256360ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Constrains the array of objects 'x' to be all different. %-----------------------------------------------------------------------------% predicate fzn_all_different_int_reif(array[int] of var int: x, var bool: b) = b <-> forall(i,j in index_set(x) where i < j) ( x[i] != x[j] ); libminizinc-2.4.2/share/minizinc/std/fzn_all_different_set.mzn000066400000000000000000000005351360574160400246270ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Constrains the array of objects 'x' to be all different. %-----------------------------------------------------------------------------% predicate fzn_all_different_set(array[int] of var set of int: x) = forall(i,j in index_set(x) where i < j) ( x[i] != x[j] ); libminizinc-2.4.2/share/minizinc/std/fzn_all_different_set_reif.mzn000066400000000000000000000005651360574160400256370ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Constrains the array of objects 'x' to be all different. %-----------------------------------------------------------------------------% predicate fzn_all_different_set_reif(array[int] of var set of int: x, var bool: b) = b <-> forall(i,j in index_set(x) where i < j) ( x[i] != x[j] ); libminizinc-2.4.2/share/minizinc/std/fzn_all_disjoint.mzn000066400000000000000000000002451360574160400236270ustar00rootroot00000000000000include "fzn_disjoint.mzn"; predicate fzn_all_disjoint(array[int] of var set of int: S) = forall(i,j in index_set(S) where i < j) ( fzn_disjoint(S[i], S[j]) ); libminizinc-2.4.2/share/minizinc/std/fzn_all_disjoint_reif.mzn000066400000000000000000000002751360574160400246370ustar00rootroot00000000000000include "fzn_disjoint.mzn"; predicate fzn_all_disjoint_reif(array[int] of var set of int: S, var bool: b) = b <-> forall(i,j in index_set(S) where i < j) ( fzn_disjoint(S[i], S[j]) ); libminizinc-2.4.2/share/minizinc/std/fzn_all_equal_int.mzn000066400000000000000000000005131360574160400237630ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Constrains the array of objects 'x' to be all equal. %-----------------------------------------------------------------------------% predicate fzn_all_equal_int(array[int] of var int: x) = forall(i, j in index_set(x) where i < j) ( x[i] = x[j] ); libminizinc-2.4.2/share/minizinc/std/fzn_all_equal_int_reif.mzn000066400000000000000000000005431360574160400247730ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Constrains the array of objects 'x' to be all equal. %-----------------------------------------------------------------------------% predicate fzn_all_equal_int_reif(array[int] of var int: x, var bool: b) = b <-> forall(i, j in index_set(x) where i < j) ( x[i] = x[j] ); libminizinc-2.4.2/share/minizinc/std/fzn_all_equal_set.mzn000066400000000000000000000005221360574160400237640ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Constrains the array of objects 'x' to be all equal. %-----------------------------------------------------------------------------% predicate fzn_all_equal_set(array[int] of var set of int: x) = forall(i, j in index_set(x) where i < j) ( x[i] = x[j] ); libminizinc-2.4.2/share/minizinc/std/fzn_all_equal_set_reif.mzn000066400000000000000000000005521360574160400247740ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Constrains the array of objects 'x' to be all equal. %-----------------------------------------------------------------------------% predicate fzn_all_equal_set_reif(array[int] of var set of int: x, var bool: b) = b <-> forall(i, j in index_set(x) where i < j) ( x[i] = x[j] ); libminizinc-2.4.2/share/minizinc/std/fzn_alldifferent_except_0.mzn000066400000000000000000000002551360574160400254030ustar00rootroot00000000000000predicate fzn_alldifferent_except_0(array[int] of var int: vs) = forall(i, j in index_set(vs) where i < j) ( (vs[i] != 0 /\ vs[j] != 0) -> vs[i] != vs[j] ); libminizinc-2.4.2/share/minizinc/std/fzn_alldifferent_except_0_reif.mzn000066400000000000000000000003051360574160400264040ustar00rootroot00000000000000predicate fzn_alldifferent_except_0_reif(array[int] of var int: vs, var bool: b) = b <-> forall(i, j in index_set(vs) where i < j) ( (vs[i] != 0 /\ vs[j] != 0) -> vs[i] != vs[j] ); libminizinc-2.4.2/share/minizinc/std/fzn_alternative.mzn000066400000000000000000000004171360574160400234730ustar00rootroot00000000000000include "span.mzn"; predicate fzn_alternative(var opt int: s0, var int: d0, array[int] of var opt int: s, array[int] of var int: d) = sum(i in index_set(s))(bool2int(occurs(s[i]))) <= 1 /\ span(s0,d0,s,d); libminizinc-2.4.2/share/minizinc/std/fzn_alternative_reif.mzn000066400000000000000000000004631360574160400245010ustar00rootroot00000000000000include "span.mzn"; predicate fzn_alternative_reif(var opt int: s0, var int: d0, array[int] of var opt int: s, array[int] of var int: d, var bool: b) = b <-> ( sum(i in index_set(s))(bool2int(occurs(s[i]))) <= 1 /\ span(s0,d0,s,d) ); libminizinc-2.4.2/share/minizinc/std/fzn_among.mzn000066400000000000000000000002051360574160400222510ustar00rootroot00000000000000predicate fzn_among(var int: n, array[int] of var int: x, set of int: v) = n == sum(i in index_set(x)) ( bool2int(x[i] in v) ); libminizinc-2.4.2/share/minizinc/std/fzn_among_reif.mzn000066400000000000000000000002401360574160400232550ustar00rootroot00000000000000predicate fzn_among_reif(var int: n, array[int] of var int: x, set of int: v, var bool: b) = b <-> ( n == sum(i in index_set(x)) ( bool2int(x[i] in v) ) ); libminizinc-2.4.2/share/minizinc/std/fzn_arg_max_bool.mzn000066400000000000000000000016351360574160400236110ustar00rootroot00000000000000predicate fzn_maximum_arg_bool(array[int] of var bool: x, var int: i) = let { int: l = min(index_set(x)); int: u = max(index_set(x)); } in if exists(j in l..u)(is_fixed(x[j]) /\ fix(x[j])) then % special case: max is known to be 1 let { array[l..u] of var bool: d; } in x[i] = true /\ % ith case must be equal to ub forall(j in l..u)(x[j] -> i <= j) /\ % lower bound d[l] = x[l] /\ forall(j in l+1..u)(d[j] <-> (d[j-1] \/ x[j])) /\ forall(j in l..u)(not d[j] -> i >= j+1) % upper bound else % general case: min could be 0 or 1 let { array[l..u] of var bool: y; array[l..u] of var l..u: mi; } in y[l] = x[l] /\ mi[l] = l /\ i = mi[u] /\ forall (j in l+1 .. u) ( y[j] == (x[j] \/ y[j-1]) /\ mi[j] = if (y[j-1] \/ not x[j]) then mi[j-1] else j endif ) endif; libminizinc-2.4.2/share/minizinc/std/fzn_arg_max_float.mzn000066400000000000000000000016351360574160400237630ustar00rootroot00000000000000predicate fzn_maximum_arg_float(array[int] of var float: x, var int: i) = let { int: l = min(index_set(x)); int: u = max(index_set(x)); float: uy = ub_array(x); } in if exists(j in l..u)(lb(x[j]) = uy) then let { array[l..u] of var bool: d; } in % max is known to be uy x[i] = uy /\ % ith case must be equal to ub forall(j in l..u)(x[j] = uy -> i <= j) /\ % lower bound d[l] = (x[l] = uy) /\ forall(j in l+1..u)(d[j] <-> (d[j-1] \/ (x[j] = uy))) /\ forall(j in l..u)(not d[j] -> i >= j+1) % upper bound else let { float: ly = lb_array(x); array[l..u] of var ly..uy: y; array[l..u] of var l..u: mi; } in y[l] = x[l] /\ mi[l] = l /\ i = mi[u] /\ forall (j in l+1 .. u) ( y[j] == max(x[j],y[j-1]) /\ mi[j] = if y[j-1] >= x[j] then mi[j-1] else j endif ) endif; libminizinc-2.4.2/share/minizinc/std/fzn_arg_max_int.mzn000066400000000000000000000016251360574160400234470ustar00rootroot00000000000000predicate fzn_maximum_arg_int(array[int] of var int: x, var int: i) = let { int: l = min(index_set(x)); int: u = max(index_set(x)); int: uy = ub_array(x); } in if exists(j in l..u)(lb(x[j]) = uy) then let { array[l..u] of var bool: d; } in % max is known to be uy x[i] = uy /\ % ith case must be equal to ub forall(j in l..u)(x[j] = uy -> i <= j) /\ % lower bound d[l] = (x[l] = uy) /\ forall(j in l+1..u)(d[j] <-> (d[j-1] \/ (x[j] = uy))) /\ forall(j in l..u)(not d[j] -> i >= j+1) % upper bound else let { int: ly = lb_array(x); array[l..u] of var ly..uy: y; array[l..u] of var l..u: mi; } in y[l] = x[l] /\ mi[l] = l /\ i = mi[u] /\ forall (j in l+1 .. u) ( y[j] == max(x[j],y[j-1]) /\ mi[j] = if y[j-1] >= x[j] then mi[j-1] else j endif ) endif; libminizinc-2.4.2/share/minizinc/std/fzn_arg_min_bool.mzn000066400000000000000000000016421360574160400236050ustar00rootroot00000000000000predicate fzn_minimum_arg_bool(array[int] of var bool: x, var int: i) = let { int: l = min(index_set(x)); int: u = max(index_set(x)); } in if exists(j in l..u)(is_fixed(x[j]) /\ not fix(x[j])) then % special case: min is known to be 0 let { array[l..u] of var bool: d; } in x[i] = false /\ % ith case must be equal to lb forall(j in l..u)(not x[j] -> i <= j) /\ % lower bound d[l] = x[l] /\ forall(j in l+1..u)(d[j] <-> (d[j-1] /\ x[j])) /\ forall(j in l..u)(d[j] -> i >= j+1) % upper bound else % general case: min could be 0 or 1 let { array[l..u] of var bool: y; array[l..u] of var l..u: mi; } in y[l] = x[l] /\ mi[l] = l /\ i = mi[u] /\ forall (j in l+1 .. u) ( y[j] == (x[j] /\ y[j-1]) /\ mi[j] = if (not y[j-1] \/ x[j]) then mi[j-1] else j endif ) endif;libminizinc-2.4.2/share/minizinc/std/fzn_arg_min_float.mzn000066400000000000000000000016331360574160400237570ustar00rootroot00000000000000predicate fzn_minimum_arg_float(array[int] of var float: x, var int: i) = let { int: l = min(index_set(x)); int: u = max(index_set(x)); float: ly = lb_array(x); } in if exists(j in l..u)(ub(x[j]) = ly) then let { array[l..u] of var bool: d; } in % min is known to be ly x[i] = ly /\ % ith case must be equal to ub forall(j in l..u)(x[j] = ly -> i <= j) /\ % lower bound d[l] = (x[l] != ly) /\ forall(j in l+1..u)(d[j] <-> (d[j-1] /\ (x[j] != ly))) /\ forall(j in l..u)(d[j] -> i >= j+1) % upper bound else let { float: uy = ub_array(x); array[l..u] of var ly..uy: y; array[l..u] of var l..u: mi; } in y[l] = x[l] /\ mi[l] = l /\ i = mi[u] /\ forall (j in l+1 .. u) ( y[j] == min(x[j],y[j-1]) /\ mi[j] = if y[j-1] <= x[j] then mi[j-1] else j endif ) endif; libminizinc-2.4.2/share/minizinc/std/fzn_arg_min_int.mzn000066400000000000000000000016231360574160400234430ustar00rootroot00000000000000predicate fzn_minimum_arg_int(array[int] of var int: x, var int: i) = let { int: l = min(index_set(x)); int: u = max(index_set(x)); int: ly = lb_array(x); } in if exists(j in l..u)(ub(x[j]) = ly) then let { array[l..u] of var bool: d; } in % min is known to be ly x[i] = ly /\ % ith case must be equal to ub forall(j in l..u)(x[j] = ly -> i <= j) /\ % lower bound d[l] = (x[l] != ly) /\ forall(j in l+1..u)(d[j] <-> (d[j-1] /\ (x[j] != ly))) /\ forall(j in l..u)(d[j] -> i >= j+1) % upper bound else let { int: uy = ub_array(x); array[l..u] of var ly..uy: y; array[l..u] of var l..u: mi; } in y[l] = x[l] /\ mi[l] = l /\ i = mi[u] /\ forall (j in l+1 .. u) ( y[j] == min(x[j],y[j-1]) /\ mi[j] = if y[j-1] <= x[j] then mi[j-1] else j endif ) endif; libminizinc-2.4.2/share/minizinc/std/fzn_arg_sort_float.mzn000066400000000000000000000004161360574160400241610ustar00rootroot00000000000000include "all_different.mzn"; predicate fzn_arg_sort_float(array[int] of var float:x, array[int] of var int:p) = all_different(p) /\ forall(j in 1..length(x)-1) (x[p[j]] <= x[p[j+1]] /\ (x[p[j]] == x[p[j+1]] -> p[j] < p[j+1])); libminizinc-2.4.2/share/minizinc/std/fzn_arg_sort_float_reif.mzn000066400000000000000000000005601360574160400251660ustar00rootroot00000000000000include "all_different.mzn"; predicate fzn_arg_sort_float_reif(array[int] of var float:x, array[int] of var int:p, var bool: b) = b <-> ( all_different(p) /\ forall(j in 1..length(x)-1) (x[p[j]] <= x[p[j+1]] /\ (x[p[j]] == x[p[j+1]] -> p[j] < p[j+1])) ); libminizinc-2.4.2/share/minizinc/std/fzn_arg_sort_int.mzn000066400000000000000000000004101360574160400236400ustar00rootroot00000000000000include "all_different.mzn"; predicate fzn_arg_sort_int(array[int] of var int:x, array[int] of var int:p) = all_different(p) /\ forall(j in 1..length(x)-1) (x[p[j]] <= x[p[j+1]] /\ (x[p[j]] == x[p[j+1]] -> p[j] < p[j+1])); libminizinc-2.4.2/share/minizinc/std/fzn_arg_sort_int_reif.mzn000066400000000000000000000005371360574160400246570ustar00rootroot00000000000000include "all_different.mzn"; predicate fzn_arg_sort_int_reif(array[int] of var int:x, array[int] of var int:p, var bool:b) = b <-> ( all_different(p) /\ forall(j in 1..length(x)-1) (x[p[j]] <= x[p[j+1]] /\ (x[p[j]] == x[p[j+1]] -> p[j] < p[j+1])) ); libminizinc-2.4.2/share/minizinc/std/fzn_at_least_int.mzn000066400000000000000000000005301360574160400236170ustar00rootroot00000000000000include "count_fn.mzn"; %-----------------------------------------------------------------------------% % Requires at least 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate fzn_at_least_int(int: n, array[int] of var int: x, int: v) = count(x, v) >= n; libminizinc-2.4.2/share/minizinc/std/fzn_at_least_int_reif.mzn000066400000000000000000000005571360574160400246350ustar00rootroot00000000000000include "count_fn.mzn"; %-----------------------------------------------------------------------------% % Requires at least 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate fzn_at_least_int_reif(int: n, array[int] of var int: x, int: v, var bool: b) = b <-> count(x, v) >= n; libminizinc-2.4.2/share/minizinc/std/fzn_at_least_set.mzn000066400000000000000000000005601360574160400236230ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires at least 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate fzn_at_least_set(int: n, array[int] of var set of int: x, set of int: v) = sum(i in index_set(x)) ( bool2int(x[i] == v) ) >= n; libminizinc-2.4.2/share/minizinc/std/fzn_at_least_set_reif.mzn000066400000000000000000000006101360574160400246240ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires at least 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate fzn_at_least_set_reif(int: n, array[int] of var set of int: x, set of int: v, var bool: b) = b <-> sum(i in index_set(x)) ( bool2int(x[i] == v) ) >= n; libminizinc-2.4.2/share/minizinc/std/fzn_at_most1.mzn000066400000000000000000000002241360574160400227000ustar00rootroot00000000000000predicate fzn_at_most1(array[int] of var set of int: s) = forall(i,j in index_set(s) where i < j) ( card(s[i] intersect s[j]) <= 1 ); libminizinc-2.4.2/share/minizinc/std/fzn_at_most1_reif.mzn000066400000000000000000000002571360574160400237130ustar00rootroot00000000000000predicate fzn_at_most1_reif(array[int] of var set of int: s, var bool: b) = b <-> forall(i,j in index_set(s) where i < j) ( card(s[i] intersect s[j]) <= 1 ); libminizinc-2.4.2/share/minizinc/std/fzn_at_most_int.mzn000066400000000000000000000005251360574160400234750ustar00rootroot00000000000000include "count_fn.mzn"; %-----------------------------------------------------------------------------% % Requires at most 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate fzn_at_most_int(int: n, array[int] of var int: x, int: v) = count(x,v) <= n; libminizinc-2.4.2/share/minizinc/std/fzn_at_most_int_reif.mzn000066400000000000000000000005551360574160400245050ustar00rootroot00000000000000include "count_fn.mzn"; %-----------------------------------------------------------------------------% % Requires at most 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate fzn_at_most_int_reif(int: n, array[int] of var int: x, int: v, var bool: b) = b <-> count(x,v) <= n; libminizinc-2.4.2/share/minizinc/std/fzn_at_most_set.mzn000066400000000000000000000005561360574160400235020ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires at most 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate fzn_at_most_set(int: n, array[int] of var set of int: x, set of int: v) = sum(i in index_set(x)) ( bool2int(x[i] == v) ) <= n; libminizinc-2.4.2/share/minizinc/std/fzn_at_most_set_reif.mzn000066400000000000000000000006061360574160400245030ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires at most 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate fzn_at_most_set_reif(int: n, array[int] of var set of int: x, set of int: v, var bool: b) = b <-> sum(i in index_set(x)) ( bool2int(x[i] == v) ) <= n; libminizinc-2.4.2/share/minizinc/std/fzn_bin_packing.mzn000066400000000000000000000006001360574160400234130ustar00rootroot00000000000000predicate fzn_bin_packing(int: c, array[int] of var int: bin, array[int] of int: w) = forall( b in lb_array(bin)..ub_array(bin) ) ( c >= sum ( i in index_set(bin) ) ( w[i] * bool2int( bin[i] == b ) ) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_bin_packing_capa.mzn000066400000000000000000000010071360574160400244010ustar00rootroot00000000000000predicate fzn_bin_packing_capa(array[int] of int: c, array[int] of var int: bin, array[int] of int: w) = forall( i in index_set(bin) ) ( min(index_set(c)) <= bin[i] /\ bin[i] <= max(index_set(c)) ) /\ forall( b in index_set(c) ) ( c[b] >= sum ( i in index_set(bin) ) ( w[i] * bool2int( bin[i] = b ) ) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_bin_packing_capa_reif.mzn000066400000000000000000000011001360574160400254000ustar00rootroot00000000000000predicate fzn_bin_packing_capa_reif(array[int] of int: c, array[int] of var int: bin, array[int] of int: w, var bool: b) = b <-> ( forall( i in index_set(bin) ) ( min(index_set(c)) <= bin[i] /\ bin[i] <= max(index_set(c)) ) /\ forall( b in index_set(c) ) ( c[b] >= sum ( i in index_set(bin) ) ( w[i] * bool2int( bin[i] = b ) ) )); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_bin_packing_load.mzn000066400000000000000000000010651360574160400244200ustar00rootroot00000000000000predicate fzn_bin_packing_load(array[int] of var int: load, array[int] of var int: bin, array[int] of int: w) = sum(load) = sum(w) /\ forall( i in index_set(bin) ) ( min(index_set(load)) <= bin[i] /\ bin[i] <= max(index_set(load)) ) /\ forall( b in index_set(load) ) ( load[b] = sum ( i in index_set(bin) ) ( w[i] * bool2int( bin[i] = b ) ) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_bin_packing_load_reif.mzn000066400000000000000000000011601360574160400254210ustar00rootroot00000000000000predicate fzn_bin_packing_load_reif(array[int] of var int: load, array[int] of var int: bin, array[int] of int: w, var bool: b) = b <-> ( sum(load) = sum(w) /\ forall( i in index_set(bin) ) ( min(index_set(load)) <= bin[i] /\ bin[i] <= max(index_set(load)) ) /\ forall( b in index_set(load) ) ( load[b] = sum ( i in index_set(bin) ) ( w[i] * bool2int( bin[i] = b ) ) ) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_bin_packing_reif.mzn000066400000000000000000000006561360574160400244330ustar00rootroot00000000000000predicate fzn_bin_packing_reif(int: c, array[int] of var int: bin, array[int] of int: w, var bool: b) = b <-> forall( b in lb_array(bin)..ub_array(bin) ) ( c >= sum ( i in index_set(bin) ) ( w[i] * bool2int( bin[i] == b ) ) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_bounded_dpath_enum.mzn000066400000000000000000000004701360574160400250000ustar00rootroot00000000000000include "path.mzn"; predicate fzn_bounded_dpath(array[int] of $$N: from, array[int] of $$N: to, array[int] of int: w, var $$N: s, var $$N: t, array[$$N] of var bool: ns, array[int] of var bool: es, var int: K) = dpath(from,to,s,t,ns,es) /\ K = sum(e in index_set(es))(es[e]*w[e]); libminizinc-2.4.2/share/minizinc/std/fzn_bounded_dpath_enum_reif.mzn000066400000000000000000000005341360574160400260060ustar00rootroot00000000000000include "path.mzn"; predicate fzn_bounded_dpath_reif(array[int] of $$N: from, array[int] of $$N: to, array[int] of int: w, var $$N: s, var $$N: t, array[$$N] of var bool: ns, array[int] of var bool: es, var int: K, var bool: b) = b <-> ( dpath(from,to,s,t,ns,es) /\ K = sum(e in index_set(es))(es[e]*w[e]) ); libminizinc-2.4.2/share/minizinc/std/fzn_bounded_dpath_int.mzn000066400000000000000000000004771360574160400246350ustar00rootroot00000000000000include "path.mzn"; predicate fzn_bounded_dpath(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of int: w, var int: s, var int: t, array[int] of var bool: ns, array[int] of var bool: es, var int: K) = dpath(N,E,from,to,s,t,ns,es) /\ K = sum(e in 1..E)(es[e]*w[e]); libminizinc-2.4.2/share/minizinc/std/fzn_bounded_dpath_int_reif.mzn000066400000000000000000000005431360574160400256340ustar00rootroot00000000000000include "path.mzn"; predicate fzn_bounded_dpath_reif(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of int: w, var int: s, var int: t, array[int] of var bool: ns, array[int] of var bool: es, var int: K, var bool: b) = b <-> ( dpath(N,E,from,to,s,t,ns,es) /\ K = sum(e in 1..E)(es[e]*w[e]) ); libminizinc-2.4.2/share/minizinc/std/fzn_bounded_path_enum.mzn000066400000000000000000000004661360574160400246410ustar00rootroot00000000000000include "path.mzn"; predicate fzn_bounded_path(array[int] of $$N: from, array[int] of $$N: to, array[int] of int: w, var $$N: s, var $$N: t, array[$$N] of var bool: ns, array[int] of var bool: es, var int: K) = path(from,to,s,t,ns,es) /\ K = sum(e in index_set(es))(es[e]*w[e]); libminizinc-2.4.2/share/minizinc/std/fzn_bounded_path_enum_reif.mzn000066400000000000000000000005321360574160400256400ustar00rootroot00000000000000include "path.mzn"; predicate fzn_bounded_path_reif(array[int] of $$N: from, array[int] of $$N: to, array[int] of int: w, var $$N: s, var $$N: t, array[$$N] of var bool: ns, array[int] of var bool: es, var int: K, var bool: b) = b <-> ( path(from,to,s,t,ns,es) /\ K = sum(e in index_set(es))(es[e]*w[e]) ); libminizinc-2.4.2/share/minizinc/std/fzn_bounded_path_int.mzn000066400000000000000000000004741360574160400244660ustar00rootroot00000000000000include "path.mzn"; predicate fzn_bounded_path(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of int: w, var int: s, var int: t, array[int] of var bool: ns, array[int] of var bool: es, var int: K) = path(N,E,from,to,s,t,ns,es) /\ K = sum(e in 1..E)(es[e]*w[e]); libminizinc-2.4.2/share/minizinc/std/fzn_bounded_path_int_reif.mzn000066400000000000000000000005401360574160400254650ustar00rootroot00000000000000include "path.mzn"; predicate fzn_bounded_path_reif(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of int: w, var int: s, var int: t, array[int] of var bool: ns, array[int] of var bool: es, var int: K, var bool: b) = b <-> ( path(N,E,from,to,s,t,ns,es) /\ K = sum(e in 1..E)(es[e]*w[e]) ); libminizinc-2.4.2/share/minizinc/std/fzn_circuit.mzn000066400000000000000000000010041360574160400226100ustar00rootroot00000000000000include "all_different.mzn"; predicate fzn_circuit(array[int] of var int: x) = let { set of int: S = index_set(x), int: l = min(S), int: n = card(S), array[S] of var 1..n: order } in all_different(x) /\ all_different(order) /\ forall(i in S)(x[i] != i) /\ order[l] = 1 /\ forall(i in S)(order[i] != n -> order[x[i]] = order[i] + 1) /\ forall(i in S)(order[i] == n -> x[i] = l ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_circuit_reif.mzn000066400000000000000000000003101360574160400236140ustar00rootroot00000000000000predicate fzn_circuit_reif(array[int] of var int: x, var bool: b) = abort("Reified circuit/1 is not supported."); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_connected.mzn000066400000000000000000000005251360574160400231170ustar00rootroot00000000000000include "reachable.mzn"; predicate fzn_connected(array[int] of $$N: from, array[int] of $$N: to, array[$$N] of var bool: ns, array[int] of var bool: es) = let { var index_set(ns): r } in reachable(from, to, r, ns, es); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_connected_reif.mzn000066400000000000000000000004621360574160400241240ustar00rootroot00000000000000predicate fzn_connected_reif(array[int] of $$N: from, array[int] of $$N: to, array[$$N] of var bool: ns, array[int] of var bool: es, var bool: b) = abort("Reified connected is not supported."); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_cost_mdd.mzn000066400000000000000000000057361360574160400227620ustar00rootroot00000000000000predicate fzn_cost_mdd(array[int] of var int: x, % variables constrained by MDD int: N, % number of nodes root is node 1 array[int] of int: level, % level of each node root is level 1, T is level length(x)+1 int: E, % number of edges array[int] of int: from, % edge leaving node 1..N array[int] of set of int: label, % values of variable on edge array[int] of int: cost, % cost of using edge array[int] of int: to, % edge entering node 0..N where 0 = T node var int: totalcost % total cost of path ) = let { set of int: NODE = 1..N; set of int: EDGE = 1..E; int: L = length(x); array[1..L] of int: maxlevelcost = [ max(e in EDGE where level[from[e]] = l)(cost[e]) | l in 1..L]; array[1..L] of int: minlevelcost = [ min([0] ++ [ cost[e] | e in EDGE where level[from[e]] = l /\ cost[e] < 0])| l in 1..L] ; int: maxcost = sum(maxlevelcost); set of int: COST = sum(minlevelcost)..L*(maxcost+1); array[0..N] of var bool: bn; array[EDGE] of var bool: be; array[0..N] of var COST: ln; % distance from T array[0..N] of var COST: un; % distance from root } in bn[0] /\ % true node is true bn[1] /\ % root must hold % T1 each node except the root enforces an outgoing edge forall(n in NODE)(bn[n] -> exists(e in EDGE where from[e] = n)(be[e])) /\ % T23 each edge enforces its endpoints forall(e in EDGE)((be[e] -> bn[to[e]]) /\ (be[e] -> bn[to[e]])) /\ % T4 each edge enforces its label forall(e in EDGE)(be[e] -> x[level[from[e]]] in label[e]) /\ % P1 each node enforces its outgoing edges forall(e in EDGE)(bn[from[e]] /\ x[level[from[e]]] in label[e] -> be[e]) /\ % P2 each node except the root enforces an incoming edge exists(e in EDGE where to[e] = 0)(be[e]) /\ forall(n in 2..N)(bn[n] -> exists(e in EDGE where to[e] = n)(be[e])) /\ % P3 each label has a support forall(i in 1..L, d in dom(x[i])) (x[i] = d -> exists(e in EDGE where level[from[e]] = i /\ d in label[e])(be[e])) /\ % P4 exactly one node at each level forall(i in 1..L) (sum(n in NODE where level[n] = i)(bn[n]) = 1) /\ ln[0] = 0 /\ un[1] = 0 /\ forall(n in NODE) (ln[n] = min(e in EDGE where from[e] = n)(ln[to[e]] + cost[e] + (not be[e])*(maxcost+1 - cost[e]))) /\ forall(n in 2..N) (un[n] = min(e in EDGE where to[e] = n)(un[from[e]] + cost[e] + (not be[e])*(maxcost+1 - cost[e]))) /\ forall(e in EDGE)(be[e] -> un[from[e]] + cost[e] + ln[to[e]] <= maxcost) /\ totalcost = ln[1]; libminizinc-2.4.2/share/minizinc/std/fzn_cost_mdd_reif.mzn000066400000000000000000000015671360574160400237650ustar00rootroot00000000000000predicate fzn_cost_mdd_reif(array[int] of var int: x, % variables constrained by MDD int: N, % number of nodes root is node 1 array[int] of int: level, % level of each node root is level 1, T is level length(x)+1 int: E, % number of edges array[int] of int: from, % edge leaving node 1..N array[int] of set of int: label, % values of variable on edge array[int] of int: cost, % cost of using edge array[int] of int: to, % edge entering node 0..N where 0 = T node var int: totalcost, % total cost of path var bool: b % reification variable ) = abort("Reified cost_mdd/9 is not supported."); libminizinc-2.4.2/share/minizinc/std/fzn_cost_regular.mzn000066400000000000000000000023411360574160400236440ustar00rootroot00000000000000predicate fzn_cost_regular(array[int] of var int: x, int: Q, int: S, array[int,int] of int: d, int: q0, set of int: F, array[int,int] of int: c, var int: C) = let { % If x has index set m..n-1, then a[m] holds the initial state % (q0), and a[i+1] holds the state we're in after processing % x[i]. If a[n] is in F, then we succeed (ie. accept the string). int: m = min(index_set(x)); int: n = max(index_set(x)) + 1; array[m..n] of var 1..Q: a; % cc[i+1] holds the accumulated cost of edges taken process up to x[i] array[m..n] of var int: cc; } in a[m] = q0 /\ % Set a[0]. cc[m] = 0 /\ % initially zero cost forall(i in index_set(x)) ( x[i] in 1..S /\ % Do this in case it's a var. a[i+1] = d[a[i], x[i]] /\ % Determine a[i+1]. cc[i+1] = c[a[i],x[i]] + cc[i] % Calculate new cost sum ) /\ a[n] in F /\ % Check the final state is in F. C = cc[n] % return final cost ; libminizinc-2.4.2/share/minizinc/std/fzn_cost_regular_reif.mzn000066400000000000000000000004341360574160400246520ustar00rootroot00000000000000predicate fzn_cost_regular_reif(array[int] of var int: x, int: Q, int: S, array[int,int] of int: d, int: q0, set of int: F, array[int,int] of int: c, var int: C, var bool: b) = abort("Reified cost_regular is not supported."); libminizinc-2.4.2/share/minizinc/std/fzn_count_eq.mzn000066400000000000000000000003241360574160400227670ustar00rootroot00000000000000predicate fzn_count_eq(array[int] of var int: x, var int: y, var int: c) = c = sum(i in index_set(x)) ( bool2int(x[i] == y) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_eq_par.mzn000066400000000000000000000003201360574160400236250ustar00rootroot00000000000000predicate fzn_count_eq_par(array[int] of var int: x, int: y, int: c) = c = sum(i in index_set(x)) ( bool2int(x[i] == y) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_eq_par_reif.mzn000066400000000000000000000003051360574160400246350ustar00rootroot00000000000000predicate fzn_count_eq_par_reif(array[int] of var int: x, int: y, int: c, var bool: b) = b <-> count_eq(x,y)=c; %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_eq_reif.mzn000066400000000000000000000003111360574160400237700ustar00rootroot00000000000000predicate fzn_count_eq_reif(array[int] of var int: x, var int: y, var int: c, var bool: b) = b <-> count_eq(x,y)=c; %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_geq.mzn000066400000000000000000000005511360574160400231400ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_geq(array[int] of var int: x, var int: y, var int: c) = let { var int: z = count(x,y) } in z <= c; % This needs to be written with a let rather than count(x,y) <= c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_geq_par.mzn000066400000000000000000000005451360574160400240050ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_geq_par(array[int] of var int: x, int: y, int: c) = let { var int: z = count(x,y) } in z <= c; % This needs to be written with a let rather than count(x,y) <= c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_geq_par_reif.mzn000066400000000000000000000005751360574160400250150ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_geq_par_reif(array[int] of var int: x, int: y, int: c, var bool: b) = let { var int: z = count(x,y) } in b <-> z <= c; % This needs to be written with a let rather than count(x,y) <= c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_geq_reif.mzn000066400000000000000000000006011360574160400241410ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_geq_reif(array[int] of var int: x, var int: y, var int: c, var bool: b) = let { var int: z = count(x,y) } in b <-> z <= c; % This needs to be written with a let rather than count(x,y) <= c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_gt.mzn000066400000000000000000000005461360574160400230020ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_gt(array[int] of var int: x, var int: y, var int: c) = let { var int: z = count(x,y) } in z < c; % This needs to be written with a let rather than count(x,y) < c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_gt_par.mzn000066400000000000000000000005421360574160400236400ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_gt_par(array[int] of var int: x, int: y, int: c) = let { var int: z = count(x,y) } in z < c; % This needs to be written with a let rather than count(x,y) < c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_gt_par_reif.mzn000066400000000000000000000005721360574160400246500ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_gt_par_reif(array[int] of var int: x, int: y, int: c, var bool: b) = let { var int: z = count(x,y) } in b <-> z < c; % This needs to be written with a let rather than count(x,y) < c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_gt_reif.mzn000066400000000000000000000005761360574160400240120ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_gt_reif(array[int] of var int: x, var int: y, var int: c, var bool: b) = let { var int: z = count(x,y) } in b <-> z < c; % This needs to be written with a let rather than count(x,y) < c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_leq.mzn000066400000000000000000000005511360574160400231450ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_leq(array[int] of var int: x, var int: y, var int: c) = let { var int: z = count(x,y) } in z >= c; % This needs to be written with a let rather than count(x,y) >= c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_leq_par.mzn000066400000000000000000000005451360574160400240120ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_leq_par(array[int] of var int: x, int: y, int: c) = let { var int: z = count(x,y) } in z >= c; % This needs to be written with a let rather than count(x,y) >= c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_leq_par_reif.mzn000066400000000000000000000005751360574160400250220ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_leq_par_reif(array[int] of var int: x, int: y, int: c, var bool: b) = let { var int: z = count(x,y) } in b <-> z >= c; % This needs to be written with a let rather than count(x,y) >= c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_leq_reif.mzn000066400000000000000000000006011360574160400241460ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_leq_reif(array[int] of var int: x, var int: y, var int: c, var bool: b) = let { var int: z = count(x,y) } in b <-> z >= c; % This needs to be written with a let rather than count(x,y) >= c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_lt.mzn000066400000000000000000000005461360574160400230070ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_lt(array[int] of var int: x, var int: y, var int: c) = let { var int: z = count(x,y) } in z > c; % This needs to be written with a let rather than count(x,y) > c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_lt_par.mzn000066400000000000000000000005421360574160400236450ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_lt_par(array[int] of var int: x, int: y, int: c) = let { var int: z = count(x,y) } in z > c; % This needs to be written with a let rather than count(x,y) > c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_lt_par_reif.mzn000066400000000000000000000005721360574160400246550ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_lt_par_reif(array[int] of var int: x, int: y, int: c, var bool: b) = let { var int: z = count(x,y) } in b <-> z > c; % This needs to be written with a let rather than count(x,y) > c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_lt_reif.mzn000066400000000000000000000005761360574160400240170ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_lt_reif(array[int] of var int: x, var int: y, var int: c, var bool: b) = let { var int: z = count(x,y) } in b <-> z > c; % This needs to be written with a let rather than count(x,y) > c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_neq.mzn000066400000000000000000000005511360574160400231470ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_neq(array[int] of var int: x, var int: y, var int: c) = let { var int: z = count(x,y) } in z != c; % This needs to be written with a let rather than count(x,y) != c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_neq_par.mzn000066400000000000000000000005451360574160400240140ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_neq_par(array[int] of var int: x, int: y, int: c) = let { var int: z = count(x,y) } in z != c; % This needs to be written with a let rather than count(x,y) != c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_neq_par_reif.mzn000066400000000000000000000005751360574160400250240ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_neq_par_reif(array[int] of var int: x, int: y, int: c, var bool: b) = let { var int: z = count(x,y) } in b <-> z != c; % This needs to be written with a let rather than count(x,y) != c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_count_neq_reif.mzn000066400000000000000000000006011360574160400241500ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_count_neq_reif(array[int] of var int: x, var int: y, var int: c, var bool: b) = let { var int: z = count(x,y) } in b <-> z != c; % This needs to be written with a let rather than count(x,y) != c % so that the automatic rewriting of the latter doesn't kick in %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_cumulative.mzn000066400000000000000000000035501360574160400233340ustar00rootroot00000000000000predicate fzn_cumulative(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = let { set of int: Tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 } } in if 0==card(Tasks) then /*true*/ 0==card(index_set(s)) \/ b>=0 else let { int: early = min([ lb(s[i]) | i in Tasks ]), int: late = max([ ub(s[i]) + ub(d[i]) | i in Tasks ]) } in ( if late - early > 5000 then fzn_cumulative_task(s, d, r, b) else fzn_cumulative_time(s, d, r, b) endif ) endif ; predicate fzn_cumulative_time(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = let { set of int: Tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 }, int: early = min([ lb(s[i]) | i in Tasks ]), int: late = max([ ub(s[i]) + ub(d[i]) | i in Tasks ]) } in ( forall( t in early..late ) ( b >= sum( i in Tasks ) ( bool2int(s[i] <= t /\ t < s[i] + d[i]) * r[i] ) ) ); predicate fzn_cumulative_task(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = let { set of int: Tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 } } in ( forall( j in Tasks ) ( b >= r[j] + sum( i in Tasks where i != j ) ( bool2int(s[i] <= s[j] /\ s[j] < s[i] + d[i] ) * r[i] ) ) ); libminizinc-2.4.2/share/minizinc/std/fzn_cumulative_opt.mzn000066400000000000000000000012751360574160400242200ustar00rootroot00000000000000predicate fzn_cumulative_opt(array[int] of var opt int: s, array[int] of var int: d, array[int] of var int: r, var int: b) = let { set of int: tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 }, set of int: times = min([ lb(s[i]) | i in tasks ]) .. max([ ub(s[i]) + ub(d[i]) | i in tasks ]) } in forall( t in times ) ( b >= sum( i in tasks ) ( bool2int( occurs(s[i]) /\ deopt(s[i]) <= t /\ t < deopt(s[i]) + d[i] ) * r[i] ) ); libminizinc-2.4.2/share/minizinc/std/fzn_cumulative_opt_reif.mzn000066400000000000000000000013271360574160400252230ustar00rootroot00000000000000predicate fzn_cumulative_opt_reif(array[int] of var opt int: s, array[int] of var int: d, array[int] of var int: r, var int: b, var bool: bb) = let { set of int: tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 }, set of int: times = min([ lb(s[i]) | i in tasks ]) .. max([ ub(s[i]) + ub(d[i]) | i in tasks ]) } in bb <-> forall( t in times ) ( b >= sum( i in tasks ) ( bool2int( occurs(s[i]) /\ deopt(s[i]) <= t /\ t < deopt(s[i]) + d[i] ) * r[i] ) ); libminizinc-2.4.2/share/minizinc/std/fzn_cumulative_reif.mzn000066400000000000000000000037031360574160400243410ustar00rootroot00000000000000predicate fzn_cumulative_reif(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b, var bool: bb) = let { set of int: Tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 } } in if 0==card(Tasks) then bb <-> ( 0==card(index_set(s)) \/ b>=0 ) else let { int: early = min([ lb(s[i]) | i in Tasks ]), int: late = max([ ub(s[i]) + ub(d[i]) | i in Tasks ]) } in ( if late - early > 5000 then fzn_cumulative_task_reif(s, d, r, b, bb) else fzn_cumulative_time_reif(s, d, r, b, bb) endif ) endif ; predicate fzn_cumulative_time_reif(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b, var bool: bb) = let { set of int: Tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 }, int: early = min([ lb(s[i]) | i in Tasks ]), int: late = max([ ub(s[i]) + ub(d[i]) | i in Tasks ]) } in ( bb <-> forall( t in early..late ) ( b >= sum( i in Tasks ) ( bool2int(s[i] <= t /\ t < s[i] + d[i]) * r[i] ) ) ); predicate fzn_cumulative_task_reif(array[int] of var int: s, array[int] of var int: d, array[int] of var int: r, var int: b, var bool: bb) = let { set of int: Tasks = {i | i in index_set(s) where ub(r[i]) > 0 /\ ub(d[i]) > 0 } } in ( bb <-> forall( j in Tasks ) ( b >= r[j] + sum( i in Tasks where i != j ) ( bool2int(s[i] <= s[j] /\ s[j] < s[i] + d[i] ) * r[i] ) ) ); libminizinc-2.4.2/share/minizinc/std/fzn_dag.mzn000066400000000000000000000011631360574160400217070ustar00rootroot00000000000000predicate fzn_dag(array[int] of $$N: from, array[int] of $$N: to, array[$$N] of var bool: ns, array[int] of var bool: es) = let { set of int: EDGE = index_set(es); array[index_set(ns)] of var 0..length(ns)-1: dist; /* distance of longest path */ } in forall(n in index_set(ns))(not ns[n] -> dist[n] = 0) /\ forall(e in EDGE) (es[e] -> dist[from[e]] + 1 <= dist[to[e]]) /\ % redundant constraint to ensure all distances are fixed forall(n in index_set(ns)) (dist[n] = max( [0] ++ [ (dist[from[e]] + 1)*es[e] | e in EDGE where to[e] = n ])) ; libminizinc-2.4.2/share/minizinc/std/fzn_dag_reif.mzn000066400000000000000000000003141360574160400227110ustar00rootroot00000000000000predicate fzn_dag_reif(array[int] of $$N: from, array[int] of $$N: to, array[$$N] of var bool: ns, array[int] of var bool: es, var bool: b) = abort("Reified dag is not supported"); libminizinc-2.4.2/share/minizinc/std/fzn_dconnected.mzn000066400000000000000000000005271360574160400232650ustar00rootroot00000000000000include "reachable.mzn"; predicate fzn_dconnected(array[int] of $$N: from, array[int] of $$N: to, array[$$N] of var bool: ns, array[int] of var bool: es) = let { var index_set(ns): r } in dreachable(from, to, r, ns, es); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_dconnected_reif.mzn000066400000000000000000000005161360574160400242700ustar00rootroot00000000000000predicate fzn_dconnected_reif(array[int] of $$N: from, array[int] of $$N: to, array[$$N] of var bool: ns, array[int] of var bool: es, var bool: b) = abort("Reified dconnected is not supported."); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_decreasing_bool.mzn000066400000000000000000000005661360574160400243010ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in decreasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate fzn_decreasing_bool(array[int] of var bool: x) = forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] >= x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_decreasing_bool_reif.mzn000066400000000000000000000006161360574160400253020ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in decreasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate fzn_decreasing_bool_reif(array[int] of var bool: x, var bool: b) = b <-> forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] >= x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_decreasing_float.mzn000066400000000000000000000005701360574160400244460ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in decreasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate fzn_decreasing_float(array[int] of var float: x) = forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] >= x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_decreasing_float_reif.mzn000066400000000000000000000006201360574160400254470ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in decreasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate fzn_decreasing_float_reif(array[int] of var float: x, var bool: b) = b <-> forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] >= x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_decreasing_int.mzn000066400000000000000000000005651360574160400241370ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in decreasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate fzn_decreasing_int(array[int] of var int: x) = forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] >= x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_decreasing_int_reif.mzn000066400000000000000000000006151360574160400251400ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in decreasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate fzn_decreasing_int_reif(array[int] of var int: x, var bool: b) = b <-> forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] >= x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_decreasing_set.mzn000066400000000000000000000005741360574160400241400ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in decreasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate fzn_decreasing_set(array[int] of var set of int: x) = forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] >= x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_decreasing_set_reif.mzn000066400000000000000000000006241360574160400251410ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in decreasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate fzn_decreasing_set_reif(array[int] of var set of int: x, var bool: b) = b <-> forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] >= x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_diffn.mzn000066400000000000000000000006421360574160400222430ustar00rootroot00000000000000predicate fzn_diffn(array[int] of var int: x, array[int] of var int: y, array[int] of var int: dx, array[int] of var int: dy) = forall(i,j in index_set(x) where i < j)( x[i] + dx[i] <= x[j] \/ y[i] + dy[i] <= y[j] \/ x[j] + dx[j] <= x[i] \/ y[j] + dy[j] <= y[i] ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_diffn_k.mzn000066400000000000000000000015071360574160400225560ustar00rootroot00000000000000predicate fzn_diffn_k(array[int,int] of var int: box_posn, array[int,int] of var int: box_size) = let { set of int: DIMS= index_set_2of2(box_posn) } in forall(b1, b2 in index_set_1of2(box_posn) where b1 < b2) (fzn_diffn_nonoverlap_k([ box_posn[b1,j] | j in DIMS ], [ box_size[b1,j] | j in DIMS ], [ box_posn[b2,j] | j in DIMS ], [ box_size[b2,j] | j in DIMS ] ) ); predicate fzn_diffn_nonoverlap_k(array[int] of var int: x1, array[int] of var int: w1, array[int] of var int: x2, array[int] of var int: w2) = exists(j in index_set(x1)) (x1[j] + w1[j] <= x2[j] \/ x2[j] + w2[j] <= x1[j]); libminizinc-2.4.2/share/minizinc/std/fzn_diffn_k_reif.mzn000066400000000000000000000015611360574160400235630ustar00rootroot00000000000000predicate fzn_diffn_k_reif(array[int,int] of var int: box_posn, array[int,int] of var int: box_size, var bool: b) = let { set of int: DIMS= index_set_2of2(box_posn) } in b <-> forall(b1, b2 in index_set_1of2(box_posn) where b1 < b2) (fzn_diffn_nonoverlap_k_for_reif([ box_posn[b1,j] | j in DIMS ], [ box_size[b1,j] | j in DIMS ], [ box_posn[b2,j] | j in DIMS ], [ box_size[b2,j] | j in DIMS ] ) ); predicate fzn_diffn_nonoverlap_k_for_reif(array[int] of var int: x1, array[int] of var int: w1, array[int] of var int: x2, array[int] of var int: w2) = exists(j in index_set(x1)) (x1[j] + w1[j] <= x2[j] \/ x2[j] + w2[j] <= x1[j]); libminizinc-2.4.2/share/minizinc/std/fzn_diffn_nonstrict.mzn000066400000000000000000000006611360574160400243470ustar00rootroot00000000000000predicate fzn_diffn_nonstrict(array[int] of var int: x, array[int] of var int: y, array[int] of var int: dx, array[int] of var int: dy) = forall(i,j in index_set(x) where i < j)( dx[i] = 0 \/ dx[j] = 0 \/ dy[i]=0 \/ dy[j]=0 \/ x[i] + dx[i] <= x[j] \/ y[i] + dy[i] <= y[j] \/ x[j] + dx[j] <= x[i] \/ y[j] + dy[j] <= y[i] ); libminizinc-2.4.2/share/minizinc/std/fzn_diffn_nonstrict_k.mzn000066400000000000000000000017161360574160400246630ustar00rootroot00000000000000predicate fzn_diffn_nonstrict_k(array[int,int] of var int: box_posn, array[int,int] of var int: box_size) = let { set of int: DIMS= index_set_2of2(box_posn) } in forall(b1, b2 in index_set_1of2(box_posn) where b1 < b2) (fzn_diffn_nonstrict_nonoverlap_k([ box_posn[b1,j] | j in DIMS ], [ box_size[b1,j] | j in DIMS ], [ box_posn[b2,j] | j in DIMS ], [ box_size[b2,j] | j in DIMS ] ) ) ; predicate fzn_diffn_nonstrict_nonoverlap_k(array[int] of var int: x1, array[int] of var int: w1, array[int] of var int: x2, array[int] of var int: w2) = exists(j in index_set(x1)) (w1[j] = 0 \/ w2[j] = 0 \/ x1[j] + w1[j] <= x2[j] \/ x2[j] + w2[j] <= x1[j]); libminizinc-2.4.2/share/minizinc/std/fzn_diffn_nonstrict_k_reif.mzn000066400000000000000000000017701360574160400256700ustar00rootroot00000000000000predicate fzn_diffn_nonstrict_k_reif(array[int,int] of var int: box_posn, array[int,int] of var int: box_size, var bool: b) = let { set of int: DIMS= index_set_2of2(box_posn) } in b <-> forall(b1, b2 in index_set_1of2(box_posn) where b1 < b2) (fzn_diffn_nonstrict_nonoverlap_k_for_reif([ box_posn[b1,j] | j in DIMS ], [ box_size[b1,j] | j in DIMS ], [ box_posn[b2,j] | j in DIMS ], [ box_size[b2,j] | j in DIMS ] ) ) ; predicate fzn_diffn_nonstrict_nonoverlap_k_for_reif(array[int] of var int: x1, array[int] of var int: w1, array[int] of var int: x2, array[int] of var int: w2) = exists(j in index_set(x1)) (w1[j] = 0 \/ w2[j] = 0 \/ x1[j] + w1[j] <= x2[j] \/ x2[j] + w2[j] <= x1[j]); libminizinc-2.4.2/share/minizinc/std/fzn_diffn_nonstrict_reif.mzn000066400000000000000000000007431360574160400253550ustar00rootroot00000000000000predicate fzn_diffn_nonstrict_reif(array[int] of var int: x, array[int] of var int: y, array[int] of var int: dx, array[int] of var int: dy, var bool: b) = b <-> forall(i,j in index_set(x) where i < j)( dx[i] = 0 \/ dx[j] = 0 \/ dy[i]=0 \/ dy[j]=0 \/ x[i] + dx[i] <= x[j] \/ y[i] + dy[i] <= y[j] \/ x[j] + dx[j] <= x[i] \/ y[j] + dy[j] <= y[i] ); libminizinc-2.4.2/share/minizinc/std/fzn_diffn_reif.mzn000066400000000000000000000007121360574160400232460ustar00rootroot00000000000000predicate fzn_diffn_reif(array[int] of var int: x, array[int] of var int: y, array[int] of var int: dx, array[int] of var int: dy, var bool: b) = b <-> forall(i,j in index_set(x) where i < j)( x[i] + dx[i] <= x[j] \/ y[i] + dy[i] <= y[j] \/ x[j] + dx[j] <= x[i] \/ y[j] + dy[j] <= y[i] ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_disjoint.mzn000066400000000000000000000001341360574160400227740ustar00rootroot00000000000000predicate fzn_disjoint(var set of int: s1, var set of int: s2) = s1 intersect s2 == {}; libminizinc-2.4.2/share/minizinc/std/fzn_disjoint_reif.mzn000066400000000000000000000001641360574160400240040ustar00rootroot00000000000000predicate fzn_disjoint_reif(var set of int: s1, var set of int: s2, var bool: b) = b <-> s1 intersect s2 == {}; libminizinc-2.4.2/share/minizinc/std/fzn_disjunctive.mzn000066400000000000000000000004331360574160400235020ustar00rootroot00000000000000predicate fzn_disjunctive(array[int] of var int: s, array[int] of var int: d) = forall (i in index_set(d)) (d[i] >= 0) /\ forall (i,j in index_set(d) where i forall (i,j in index_set(d) where i ( forall (i in index_set(d)) (d[i] >= 0) /\ forall (i,j in index_set(d) where i= 0) /\ forall (i,j in index_set(d) where i= 0) /\ forall (i,j in index_set(d) where i ( forall (i in index_set(d)) (d[i] >= 0) /\ forall (i,j in index_set(d) where i ( forall (i in index_set(d)) (d[i] >= 0) /\ forall (i,j in index_set(d) where i forall (i in index_set(card)) ( card[i] == sum(j in index_set(base)) ( bool2int(value[i] = base[j]) ) ); libminizinc-2.4.2/share/minizinc/std/fzn_dpath_enum.mzn000066400000000000000000000033221360574160400232770ustar00rootroot00000000000000include "tree.mzn"; include "subgraph.mzn"; predicate fzn_dpath(array[int] of $$N: from, array[int] of $$N: to, var $$N: s, var $$N: t, array[$$N] of var bool: ns, array[int] of var bool: es) = let { set of int: EDGE = index_set(es); array[index_set(ns)] of var 0..length(ns)-1: dist; /* distance from root */ } in ns[s] /\ % source is selected ns[t] /\ % dest is selected dist[s] = 0 /\ % distance of source is zero forall(n in index_set(ns)) % nonselected nodes have distance 0 (not ns[n] -> dist[n] = 0) /\ forall(n in index_set(ns)) % 1 incoming edge ((ns[n] /\ n != s) -> exists(e in EDGE where to[e] = n)(es[e])) /\ forall(n in index_set(ns)) % 1 outgoing edge ((ns[n] /\ n != t) -> exists(e in EDGE where from[e] = n)(es[e])) /\ forall(n in index_set(ns)) % 1 incoming edge ((ns[n] /\ n != s) -> sum(e in EDGE where to[e] = n)(es[e]) <= 1) /\ forall(n in index_set(ns)) % 1 outgoing edge ((ns[n] /\ n != t) -> sum(e in EDGE where from[e] = n)(es[e]) <= 1) /\ % alternate for the previous 8 lines % forall(n in index_set(ns)) % 1 incoming edge % ((ns[n] /\ n != s) -> sum(e in EDGE where to[e] = n)(es[e]) = 1) /\ % forall(n in index_set(ns)) % 1 outgoing edge % ((ns[n] /\ n != t) -> sum(e in EDGE where from[e] = n)(es[e]) = 1) /\ forall(e in EDGE) (es[e] -> dist[to[e]] = dist[from[e]] + 1) /\ sum(n in index_set(ns))(ns[n]) = sum(e in EDGE)(es[e]) + 1 /\ subgraph(from,to,ns,es); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_dpath_enum_reif.mzn000066400000000000000000000005121360574160400243020ustar00rootroot00000000000000predicate fzn_dpath_reif(array[int] of $$N: from, array[int] of $$N: to, var $$N: s, var $$N: t, array[$$N] of var bool: ns, array[int] of var bool: es, var bool: b) = abort("Reified dpath constraint is not supported"); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_dpath_int.mzn000066400000000000000000000005721360574160400231310ustar00rootroot00000000000000include "tree.mzn"; include "subgraph.mzn"; predicate fzn_dpath(int: N, int: E, array[int] of int: from, array[int] of int: to, var int: s, var int: t, array[int] of var bool: ns, array[int] of var bool: es) = dtree(N,E,from,to,s,ns,es) /\ dtree(N,E,to,from,t,ns,es); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_dpath_int_reif.mzn000066400000000000000000000006741360574160400241410ustar00rootroot00000000000000include "tree.mzn"; include "subgraph.mzn"; predicate fzn_dpath_reif(int: N, int: E, array[int] of int: from, array[int] of int: to, var int: s, var int: t, array[int] of var bool: ns, array[int] of var bool: es, var bool: b) = b <-> ( dtree(N,E,from,to,s,ns,es) /\ dtree(N,E,to,from,t,ns,es) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_dreachable_enum.mzn000066400000000000000000000027461360574160400242620ustar00rootroot00000000000000include "subgraph.mzn"; predicate fzn_dreachable(array[int] of $$N: from, array[int] of $$N: to, var $$N: r, array[$$N] of var bool: ns, array[int] of var bool: es) = let { array[index_set(ns)] of var 0..card(index_set(ns))-1: dist; /* distance from root */ array[index_set(ns)] of var index_set(ns): parent; /* parent */ } in ns[r] /\ % the root must be chosen dist[r] = 0 /\ % root is at distance 0 parent[r] = r /\ % root is its own parent forall(n in index_set(ns)) % nonselected nodes have parent 0 (not ns[n] -> parent[n] = n) /\ forall(n in index_set(ns)) % nonselected nodes have distance 0 (not ns[n] -> dist[n] = 0) /\ forall(n in index_set(ns)) % each in node except root must have a parent (ns[n] -> (n = r \/ parent[n] != n)) /\ forall(n in index_set(ns)) % each in node with a parent must be in and also its parent (parent[n] != n -> (ns[n] /\ ns[parent[n]])) /\ forall(n in index_set(ns)) % each except with a parent is one more than its parent (parent[n] != n -> dist[n] = dist[parent[n]] + 1) /\ forall(n in index_set(ns)) % each node with a parent must have that edge in (parent[n] != n -> exists(e in index_set(from) where to[e] = n)(es[e] /\ from[e] = parent[n])) /\ subgraph(from,to,ns,es); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_dreachable_enum_reif.mzn000066400000000000000000000005541360574160400252620ustar00rootroot00000000000000predicate fzn_dreachable_reif(array[int] of $$N: from, array[int] of $$N: to, var $$N: r, array[$$N] of var bool: ns, array[int] of var bool: es, var bool: b) = abort("Reified dreachable constraint is not supported"); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_dreachable_int.mzn000066400000000000000000000026331360574160400241030ustar00rootroot00000000000000include "subgraph.mzn"; predicate fzn_dreachable(int: N, int: E, array[int] of int: from, array[int] of int: to, var int: r, array[int] of var bool: ns, array[int] of var bool: es) = let { set of int: NODE = 1..N; array[NODE] of var 0..N-1: dist; /* distance from root */ array[NODE] of var 0..N: parent; /* parent */ } in ns[r] /\ % the root must be chosen dist[r] = 0 /\ % root is at distance 0 forall(n in NODE) % nonselected nodes have parent 0 (not ns[n] -> parent[n] = 0) /\ forall(n in NODE) % nonselected nodes have distance 0 (not ns[n] -> dist[n] = 0) /\ forall(n in NODE) % each in node except root must have a parent (ns[n] -> (n = r \/ parent[n] > 0)) /\ forall(n in NODE) % each in node with a parent must be in and also its parent (parent[n] > 0 -> (ns[n] /\ ns[parent[n]])) /\ forall(n in NODE) % each except with a parent is one more than its parent (parent[n] > 0 -> dist[n] = dist[parent[n]] + 1) /\ forall(n in NODE) % each node with a parent must have that edge in (parent[n] > 0 -> exists(e in 1..E)(es[e] /\ from[e] = parent[n] /\ to[e] = n)) /\ subgraph(N,E,from,to,ns,es); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_dreachable_int_reif.mzn000066400000000000000000000005711360574160400251070ustar00rootroot00000000000000predicate fzn_dreachable_reif(int: N, int: E, array[int] of int: from, array[int] of int: to, var int: r, array[int] of var bool: ns, array[int] of var bool: es, var bool: b) = abort("Reified dreachable constraint is not supported"); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_dsteiner.mzn000066400000000000000000000006061360574160400227720ustar00rootroot00000000000000include "tree.mzn"; predicate fzn_dsteiner(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of int: w, var int: r, array[int] of var bool: ns, array[int] of var bool: es, var int: K) = dtree(N,E,from,to,r,ns,es) /\ K = sum(e in 1..E)(es[e]*w[e]); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_dsteiner_reif.mzn000066400000000000000000000005711360574160400240000ustar00rootroot00000000000000predicate fzn_dsteiner_reif(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of int: w, var int: r, array[int] of var bool: ns, array[int] of var bool: es, var int: K, var bool: b) = abort("Reified steiner constraint is not supported"); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_dtree_enum.mzn000066400000000000000000000033371360574160400233100ustar00rootroot00000000000000include "subgraph.mzn"; predicate fzn_dtree(array[int] of $$N: from, array[int] of $$N: to, var $$N: r, array[$$N] of var bool: ns, array[int] of var bool: es) = let { set of int: EDGE = index_set(es); array[index_set(ns)] of var 0..length(ns)-1: dist; /* distance from root */ array[index_set(ns)] of var index_set(ns): parent; /* parent */ } in ns[r] /\ % the root must be chosen dist[r] = 0 /\ % root is at distance 0 parent[r] = r /\ % root is its own parent forall(n in index_set(ns)) % nonselected nodes have parent 0 (not ns[n] -> parent[n] = n) /\ forall(n in index_set(ns)) % nonselected nodes have distance 0 (not ns[n] -> dist[n] = 0) /\ forall(n in index_set(ns)) % each in node except root must have a parent (ns[n] -> (n = r \/ parent[n] != n)) /\ forall(n in index_set(ns)) % each in node with a parent must be in and also its parent (parent[n] != n -> (ns[n] /\ ns[parent[n]])) /\ forall(n in index_set(ns)) % each except with a parent is one more than its parent (parent[n] != n -> dist[n] = dist[parent[n]] + 1) /\ forall(n in index_set(ns)) % each node with a parent must have that edge in (parent[n] != n -> exists(e in EDGE where to[e] = n)(es[e] /\ from[e] = parent[n])) /\ forall(e in EDGE) % each edge must be part of the parent relation (es[e] -> parent[to[e]] = from[e]) /\ sum(e in EDGE)(es[e]) = sum(n in index_set(ns))(ns[n]) - 1 /\ % redundant relationship of trees subgraph(from,to,ns,es); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_dtree_enum_reif.mzn000066400000000000000000000005251360574160400243110ustar00rootroot00000000000000predicate fzn_dtree_reif(array[int] of $$N: from, array[int] of $$N: to, var $$N: r, array[$$N] of var bool: ns, array[int] of var bool: es, var bool: b) = abort("Reified dtree constraint is not supported"); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_dtree_int.mzn000066400000000000000000000031341360574160400231310ustar00rootroot00000000000000include "subgraph.mzn"; predicate fzn_dtree(int: N, int: E, array[int] of int: from, array[int] of int: to, var int: r, array[int] of var bool: ns, array[int] of var bool: es) = let { set of int: NODE = 1..N; set of int: EDGE = 1..E; array[NODE] of var 0..N-1: dist; /* distance from root */ array[NODE] of var 0..N: parent; /* parent */ } in ns[r] /\ % the root must be chosen dist[r] = 0 /\ % root is at distance 0 forall(n in NODE) % nonselected nodes have parent 0 (not ns[n] -> parent[n] <= 0) /\ forall(n in NODE) % nonselected nodes have distance 0 (not ns[n] -> dist[n] = 0) /\ forall(n in NODE) % each in node except root must have a parent (ns[n] -> (n = r \/ parent[n] > 0)) /\ forall(n in NODE) % each node with a parent then parent is in (parent[n] > 0 -> (ns[n] /\ ns[parent[n]])) /\ forall(n in NODE) % each node with a parent is one more than its parent (parent[n] > 0 -> dist[n] = dist[parent[n]] + 1) /\ forall(n in NODE) % each node with a parent must have that edge in (parent[n] > 0 -> exists(e in EDGE)(es[e] /\ from[e] = parent[n] /\ to[e] = n)) /\ forall(e in EDGE) % each edge must be part of the parent relation (es[e] -> parent[to[e]] = from[e]) /\ sum(e in EDGE)(es[e]) = sum(n in NODE)(ns[n]) - 1 /\ % redundant relationship of trees subgraph(N,E,from,to,ns,es); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_dtree_int_reif.mzn000066400000000000000000000005141360574160400241350ustar00rootroot00000000000000predicate fzn_dtree_reif(int: N, int: E, array[int] of int: from, array[int] of int: to, var int: r, array[int] of var bool: ns, array[int] of var bool: es, var bool: b) = abort("Reified dtree constraint is not supported"); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_dwst.mzn000066400000000000000000000006411360574160400221350ustar00rootroot00000000000000include "tree.mzn"; predicate fzn_dwst(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of int: w, var int: r, array[int] of var bool: es, var int: K) = let { array[1..N] of bool: ns = [true | n in 1..N]; } in dtree(N,E,from,to,r,ns,es) /\ K = sum(e in 1..E)(es[e]*w[e]); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_dwst_reif.mzn000066400000000000000000000005221360574160400231400ustar00rootroot00000000000000predicate fzn_dwst_reif(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of int: w, var int: r, array[int] of var bool: es, var int: K, var bool: b) = abort("Reified dwst constraint is not supported"); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_exactly_int.mzn000066400000000000000000000005251360574160400235000ustar00rootroot00000000000000include "count_fn.mzn"; %-----------------------------------------------------------------------------% % Requires exactly 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate fzn_exactly_int(int: n, array[int] of var int: x, int: v) = n == count(x, v); libminizinc-2.4.2/share/minizinc/std/fzn_exactly_int_reif.mzn000066400000000000000000000005551360574160400245100ustar00rootroot00000000000000include "count_fn.mzn"; %-----------------------------------------------------------------------------% % Requires exactly 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate fzn_exactly_int_reif(int: n, array[int] of var int: x, int: v, var bool: b) = b <-> n == count(x, v); libminizinc-2.4.2/share/minizinc/std/fzn_exactly_set.mzn000066400000000000000000000005551360574160400235040ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires exactly 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate fzn_exactly_set(int: n, array[int] of var set of int: x, set of int: v) = n == sum(i in index_set(x)) ( bool2int(x[i] == v) ); libminizinc-2.4.2/share/minizinc/std/fzn_exactly_set_reif.mzn000066400000000000000000000006051360574160400245050ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires exactly 'n' variables in 'x' to take the value 'v'. %-----------------------------------------------------------------------------% predicate fzn_exactly_set_reif(int: n, array[int] of var set of int: x, set of int: v, var bool: b) = b <-> n == sum(i in index_set(x)) ( bool2int(x[i] == v) ); libminizinc-2.4.2/share/minizinc/std/fzn_geost.mzn000066400000000000000000000023051360574160400222740ustar00rootroot00000000000000include "fzn_geost_nonoverlap_k.mzn"; predicate fzn_geost( int : k , array[int,int] of int : rect_size , array[int,int] of int : rect_offset , array[int ] of set of int : shape , array[int,int] of var int : x , array[int ] of var int : kind ) = % A few useful definitions let { set of int: DIMS = 1..k; set of int: SHAPES = 1..length(shape); set of int: OBJECTS = index_set(kind); } in forall(o1, o2 in OBJECTS where o1 < o2)( forall(s1 in dom(kind[o1]), s2 in dom(kind[o2]))( (kind[o1] = s1 /\ kind[o2] = s2 -> forall(r1 in shape[s1], r2 in shape[s2])( fzn_geost_nonoverlap_k( [ x[o1,j] + rect_offset[r1,j] | j in DIMS ], [ rect_size[r1,j] | j in DIMS ], [ x[o2,j] + rect_offset[r2,j] | j in DIMS ], [ rect_size[r2,j] | j in DIMS ] ) ) ) ) ); libminizinc-2.4.2/share/minizinc/std/fzn_geost_bb.mzn000066400000000000000000000020501360574160400227340ustar00rootroot00000000000000predicate fzn_geost_bb( int : k , array[int,int] of int : rect_size , array[int,int] of int : rect_offset , array[int ] of set of int : shape , array[int,int] of var int : x , array[int ] of var int : kind , array[int ] of var int : l , array[int ] of var int : u ) = % Two useful definitions let { set of int: DIMS = 1..k; set of int: OBJECTS = index_set(kind); } in % Posting the geost constraint fzn_geost(k, rect_size, rect_offset, shape, x, kind) /\ % Posting the bounding box constraints forall(o in OBJECTS)( forall(s in dom(kind[o]))( (kind[o] = s -> forall(r in shape[s], j in DIMS)( x[o,j] + rect_offset[r,j] >= l[j] /\ x[o,j] + rect_offset[r,j] + rect_size[r,j] <= u[j] ) ) ) ); libminizinc-2.4.2/share/minizinc/std/fzn_geost_bb_reif.mzn000066400000000000000000000022131360574160400237420ustar00rootroot00000000000000include "fzn_geost.mzn"; include "fzn_geost_reif.mzn"; predicate fzn_geost_bb_reif( int : k , array[int,int] of int : rect_size , array[int,int] of int : rect_offset , array[int ] of set of int : shape , array[int,int] of var int : x , array[int ] of var int : kind , array[int ] of var int : l , array[int ] of var int : u , var bool: b ) = % Two useful definitions let { set of int: DIMS = 1..k; set of int: OBJECTS = index_set(kind); } in b <-> ( % Posting the geost constraint fzn_geost(k, rect_size, rect_offset, shape, x, kind) /\ % Posting the bounding box constraints forall(o in OBJECTS)( forall(s in dom(kind[o]))( (kind[o] = s -> forall(r in shape[s], j in DIMS)( x[o,j] + rect_offset[r,j] >= l[j] /\ x[o,j] + rect_offset[r,j] + rect_size[r,j] <= u[j] ) ) ) )); libminizinc-2.4.2/share/minizinc/std/fzn_geost_nonoverlap_k.mzn000066400000000000000000000004461360574160400250550ustar00rootroot00000000000000predicate fzn_geost_nonoverlap_k( array[int] of var int : x1, array[int] of int : w1, array[int] of var int : x2, array[int] of int : w2 ) = % Non-overlap constraint exists(j in index_set(x1))( x1[j] + w1[j] <= x2[j] \/ x2[j] + w2[j] <= x1[j] ); libminizinc-2.4.2/share/minizinc/std/fzn_geost_nonoverlap_k_reif.mzn000066400000000000000000000005021360574160400260530ustar00rootroot00000000000000predicate fzn_geost_nonoverlap_k_reif( array[int] of var int : x1, array[int] of int : w1, array[int] of var int : x2, array[int] of int : w2, var bool: b ) = % Non-overlap constraint b <-> exists(j in index_set(x1))( x1[j] + w1[j] <= x2[j] \/ x2[j] + w2[j] <= x1[j] ); libminizinc-2.4.2/share/minizinc/std/fzn_geost_reif.mzn000066400000000000000000000024241360574160400233030ustar00rootroot00000000000000include "fzn_geost_nonoverlap_k.mzn"; include "fzn_geost_nonoverlap_k_reif.mzn"; predicate fzn_geost_reif( int : k , array[int,int] of int : rect_size , array[int,int] of int : rect_offset , array[int ] of set of int : shape , array[int,int] of var int : x , array[int ] of var int : kind , var bool: b ) = % A few useful definitions let { set of int: DIMS = 1..k; set of int: SHAPES = 1..length(shape); set of int: OBJECTS = index_set(kind); } in b <-> forall(o1, o2 in OBJECTS where o1 < o2)( forall(s1 in dom(kind[o1]), s2 in dom(kind[o2]))( (kind[o1] = s1 /\ kind[o2] = s2 -> forall(r1 in shape[s1], r2 in shape[s2])( fzn_geost_nonoverlap_k( [ x[o1,j] + rect_offset[r1,j] | j in DIMS ], [ rect_size[r1,j] | j in DIMS ], [ x[o2,j] + rect_offset[r2,j] | j in DIMS ], [ rect_size[r2,j] | j in DIMS ] ) ) ) ) ); libminizinc-2.4.2/share/minizinc/std/fzn_geost_smallest_bb.mzn000066400000000000000000000023441360574160400246460ustar00rootroot00000000000000predicate fzn_geost_smallest_bb( int : k , array[int,int] of int : rect_size , array[int,int] of int : rect_offset , array[int ] of set of int : shape , array[int,int] of var int : x , array[int ] of var int : kind , array[int ] of var int : l , array[int ] of var int : u ) = % Two useful definitions let { set of int: DIMS = 1..k; set of int: OBJECTS = index_set(kind); } in ( % Posting the geost constraint fzn_geost_bb(k, rect_size, rect_offset, shape, x, kind, l, u) /\ % Posting the smallest bounding box constraints forall(j in DIMS)( % Lower boundary exists(o in OBJECTS, s in dom(kind[o]))( kind[o] = s /\ exists(r in shape[s])( x[o,j] + rect_offset[r,j] == l[j] ) ) /\ % Upper boundary exists(o in OBJECTS, s in dom(kind[o]))( kind[o] = s /\ exists(r in shape[s])( x[o,j] + rect_offset[r,j] + rect_size[r,j] == u[j] ) ) ) ); libminizinc-2.4.2/share/minizinc/std/fzn_geost_smallest_bb_reif.mzn000066400000000000000000000025111360574160400256470ustar00rootroot00000000000000include "fzn_geost_bb.mzn"; include "fzn_geost_bb_reif.mzn"; predicate fzn_geost_smallest_bb_reif( int : k , array[int,int] of int : rect_size , array[int,int] of int : rect_offset , array[int ] of set of int : shape , array[int,int] of var int : x , array[int ] of var int : kind , array[int ] of var int : l , array[int ] of var int : u , var bool: b ) = % Two useful definitions let { set of int: DIMS = 1..k; set of int: OBJECTS = index_set(kind); } in b <-> ( % Posting the geost constraint fzn_geost_bb(k, rect_size, rect_offset, shape, x, kind, l, u) /\ % Posting the smallest bounding box constraints forall(j in DIMS)( % Lower boundary exists(o in OBJECTS, s in dom(kind[o]))( kind[o] = s /\ exists(r in shape[s])( x[o,j] + rect_offset[r,j] == l[j] ) ) /\ % Upper boundary exists(o in OBJECTS, s in dom(kind[o]))( kind[o] = s /\ exists(r in shape[s])( x[o,j] + rect_offset[r,j] + rect_size[r,j] == u[j] ) ) ) ); libminizinc-2.4.2/share/minizinc/std/fzn_global_cardinality.mzn000066400000000000000000000004641360574160400250020ustar00rootroot00000000000000include "count.mzn"; predicate fzn_global_cardinality(array[int] of var int: x, array[int] of int: cover, array[int] of var int: counts) = forall(i in index_set(cover))( count(x, cover[i], counts[i]) ) /\ % Implied constraint length(x) >= sum(counts); libminizinc-2.4.2/share/minizinc/std/fzn_global_cardinality_closed.mzn000066400000000000000000000005251360574160400263310ustar00rootroot00000000000000include "global_cardinality.mzn"; predicate fzn_global_cardinality_closed(array[int] of var int: x, array[int] of int: cover, array[int] of var int: counts) = forall(i in index_set(x))( x[i] in { d | d in cover } ) /\ global_cardinality(x, cover, counts); libminizinc-2.4.2/share/minizinc/std/fzn_global_cardinality_closed_reif.mzn000066400000000000000000000006431360574160400273370ustar00rootroot00000000000000include "global_cardinality.mzn"; predicate fzn_global_cardinality_closed_reif(array[int] of var int: x, array[int] of int: cover, array[int] of var int: counts, var bool: b) = b <-> ( forall(i in index_set(x))( x[i] in { d | d in cover } ) /\ global_cardinality(x, cover, counts) ); libminizinc-2.4.2/share/minizinc/std/fzn_global_cardinality_low_up.mzn000066400000000000000000000005721360574160400263670ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_global_cardinality_low_up(array[int] of var int: x, array[int] of int: cover, array[int] of int: lbound, array[int] of int: ubound) = forall(i in index_set(cover))( count(x, cover[i]) in lbound[i]..ubound[i] ); libminizinc-2.4.2/share/minizinc/std/fzn_global_cardinality_low_up_closed.mzn000066400000000000000000000007731360574160400277230ustar00rootroot00000000000000predicate fzn_global_cardinality_low_up_closed(array[int] of var int: x, array[int] of int: cover, array[int] of int: lbound, array[int] of int: ubound) = forall(i in index_set(x))( x[i] in { d | d in array2set(cover) } ) /\ global_cardinality_low_up(x, cover, lbound, ubound) /\ % Implied condition length(x) in sum(lbound)..sum(ubound); include "global_cardinality_low_up.mzn"; libminizinc-2.4.2/share/minizinc/std/fzn_global_cardinality_low_up_closed_reif.mzn000066400000000000000000000012011360574160400307130ustar00rootroot00000000000000predicate fzn_global_cardinality_low_up_closed_reif(array[int] of var int: x, array[int] of int: cover, array[int] of int: lbound, array[int] of int: ubound, var bool: b) = b <-> ( forall(i in index_set(x))( x[i] in { d | d in array2set(cover) } ) /\ global_cardinality_low_up(x, cover, lbound, ubound) /\ % Implied condition length(x) in sum(lbound)..sum(ubound)); include "global_cardinality_low_up.mzn"; libminizinc-2.4.2/share/minizinc/std/fzn_global_cardinality_low_up_reif.mzn000066400000000000000000000007161360574160400273740ustar00rootroot00000000000000include "count_fn.mzn"; predicate fzn_global_cardinality_low_up_reif(array[int] of var int: x, array[int] of int: cover, array[int] of int: lbound, array[int] of int: ubound, var bool: b) = b <-> forall(i in index_set(cover))( count(x, cover[i]) in lbound[i]..ubound[i] ); libminizinc-2.4.2/share/minizinc/std/fzn_global_cardinality_reif.mzn000066400000000000000000000006201360574160400260010ustar00rootroot00000000000000include "count.mzn"; predicate fzn_global_cardinality_reif(array[int] of var int: x, array[int] of int: cover, array[int] of var int: counts, var bool: b) = b <-> ( forall(i in index_set(cover))( count(x, cover[i], counts[i]) ) /\ % Implied constraint length(x) >= sum(counts) ); libminizinc-2.4.2/share/minizinc/std/fzn_if_then_else_bool.mzn000066400000000000000000000005571360574160400246210ustar00rootroot00000000000000predicate fzn_if_then_else_bool(array[int] of var bool: c, array[int] of bool: x, var bool: y) = let { array[index_set(c)] of var bool: d; } in forall(i in index_set(c)) (if i > min(index_set(c)) then d[i] = (not c[i-1] /\ d[i-1]) else d[i] = true endif) /\ forall (i in index_set(c)) (c[i] /\ d[i] -> y=x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_if_then_else_float.mzn000066400000000000000000000005621360574160400247670ustar00rootroot00000000000000predicate fzn_if_then_else_float(array[int] of var bool: c, array[int] of float: x, var float: y) = let { array[index_set(c)] of var bool: d; } in forall(i in index_set(c)) (if i > min(index_set(c)) then d[i] = (not c[i-1] /\ d[i-1]) else d[i] = true endif) /\ forall (i in index_set(c)) (c[i] /\ d[i] -> y=x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_if_then_else_int.mzn000066400000000000000000000005541360574160400244550ustar00rootroot00000000000000predicate fzn_if_then_else_int(array[int] of var bool: c, array[int] of int: x, var int: y) = let { array[index_set(c)] of var bool: d; } in forall(i in index_set(c)) (if i > min(index_set(c)) then d[i] = (not c[i-1] /\ d[i-1]) else d[i] = true endif) /\ forall (i in index_set(c)) (c[i] /\ d[i] -> y=x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_if_then_else_opt_bool.mzn000066400000000000000000000005441360574160400254770ustar00rootroot00000000000000include "fzn_if_then_else_bool.mzn"; include "fzn_if_then_else_var_bool.mzn"; predicate fzn_if_then_else_opt_bool(array[int] of var bool: c, array[int] of opt bool: x, var opt bool: y) = fzn_if_then_else_bool(array1d(c),[deopt(x[i]) | i in index_set(x)],deopt(y)) /\ fzn_if_then_else_var_bool(array1d(c),[occurs(x[i]) | i in index_set(x)],occurs(y)); libminizinc-2.4.2/share/minizinc/std/fzn_if_then_else_opt_float.mzn000066400000000000000000000005511360574160400256470ustar00rootroot00000000000000include "fzn_if_then_else_float.mzn"; include "fzn_if_then_else_var_bool.mzn"; predicate fzn_if_then_else_opt_float(array[int] of var bool: c, array[int] of opt float: x, var opt float: y) = fzn_if_then_else_float(array1d(c),[deopt(x[i]) | i in index_set(x)],deopt(y)) /\ fzn_if_then_else_var_bool(array1d(c),[occurs(x[i]) | i in index_set(x)],occurs(y)); libminizinc-2.4.2/share/minizinc/std/fzn_if_then_else_opt_int.mzn000066400000000000000000000005371360574160400253400ustar00rootroot00000000000000include "fzn_if_then_else_int.mzn"; include "fzn_if_then_else_var_bool.mzn"; predicate fzn_if_then_else_opt_int(array[int] of var bool: c, array[int] of opt int: x, var opt int: y) = fzn_if_then_else_int(array1d(c),[deopt(x[i]) | i in index_set(x)],deopt(y)) /\ fzn_if_then_else_var_bool(array1d(c),[occurs(x[i]) | i in index_set(x)],occurs(y)); libminizinc-2.4.2/share/minizinc/std/fzn_if_then_else_partiality.mzn000066400000000000000000000007101360574160400260370ustar00rootroot00000000000000predicate fzn_if_then_else_partiality(array[int] of var bool: c, array[int] of var bool: def, var bool: b) = let { array[index_set(c)] of var bool: d; } in forall(i in index_set(c)) (if i > min(index_set(c)) then d[i] = (not c[i-1] /\ d[i-1]) else d[i] = true endif) /\ forall(i in index_set(c)) ( (b /\ c[i] /\ d[i] -> def[i])) /\ forall (i in index_set(c)) (d[i] /\ c[i] /\ def[i] -> b); libminizinc-2.4.2/share/minizinc/std/fzn_if_then_else_set.mzn000066400000000000000000000005721360574160400244560ustar00rootroot00000000000000predicate fzn_if_then_else_set(array[int] of var bool: c, array[int] of set of int: x, var set of int: y) = let { array[index_set(c)] of var bool: d; } in forall(i in index_set(c)) (if i > min(index_set(c)) then d[i] = (not c[i-1] /\ d[i-1]) else d[i] = true endif) /\ forall (i in index_set(c)) (c[i] /\ d[i] -> y=x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_if_then_else_var_bool.mzn000066400000000000000000000005671360574160400254720ustar00rootroot00000000000000predicate fzn_if_then_else_var_bool(array[int] of var bool: c, array[int] of var bool: x, var bool: y) = let { array[index_set(c)] of var bool: d; } in forall(i in index_set(c)) (if i > min(index_set(c)) then d[i] = (not c[i-1] /\ d[i-1]) else d[i] = true endif) /\ forall (i in index_set(c)) (c[i] /\ d[i] -> y=x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_if_then_else_var_float.mzn000066400000000000000000000005721360574160400256400ustar00rootroot00000000000000predicate fzn_if_then_else_var_float(array[int] of var bool: c, array[int] of var float: x, var float: y) = let { array[index_set(c)] of var bool: d; } in forall(i in index_set(c)) (if i > min(index_set(c)) then d[i] = (not c[i-1] /\ d[i-1]) else d[i] = true endif) /\ forall (i in index_set(c)) (c[i] /\ d[i] -> y=x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_if_then_else_var_int.mzn000066400000000000000000000005641360574160400253260ustar00rootroot00000000000000predicate fzn_if_then_else_var_int(array[int] of var bool: c, array[int] of var int: x, var int: y) = let { array[index_set(c)] of var bool: d; } in forall(i in index_set(c)) (if i > min(index_set(c)) then d[i] = (not c[i-1] /\ d[i-1]) else d[i] = true endif) /\ forall (i in index_set(c)) (c[i] /\ d[i] -> y=x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_if_then_else_var_opt_bool.mzn000066400000000000000000000005371360574160400263510ustar00rootroot00000000000000include "fzn_if_then_else_var_bool.mzn"; predicate fzn_if_then_else_var_opt_bool(array[int] of var bool: c, array[int] of var opt bool: x, var opt bool: y) = fzn_if_then_else_var_bool(array1d(c),[deopt_bool(x[i]) | i in index_set(x)],deopt_bool(y)) /\ fzn_if_then_else_var_bool(array1d(c),[occurs_bool(x[i]) | i in index_set(x)],occurs_bool(y)); libminizinc-2.4.2/share/minizinc/std/fzn_if_then_else_var_opt_float.mzn000066400000000000000000000006211360574160400265150ustar00rootroot00000000000000include "fzn_if_then_else_var_bool.mzn"; include "fzn_if_then_else_var_float.mzn"; predicate fzn_if_then_else_var_opt_float(array[int] of var bool: c, array[int] of var opt float: x, var opt float: y) = fzn_if_then_else_var_float(array1d(c),[deopt_float(x[i]) | i in index_set(x)],deopt_float(y)) /\ fzn_if_then_else_var_bool(array1d(c),[occurs_float(x[i]) | i in index_set(x)],occurs_float(y)); libminizinc-2.4.2/share/minizinc/std/fzn_if_then_else_var_opt_int.mzn000066400000000000000000000005771360574160400262140ustar00rootroot00000000000000include "fzn_if_then_else_var_bool.mzn"; include "fzn_if_then_else_var_int.mzn"; predicate fzn_if_then_else_var_opt_int(array[int] of var bool: c, array[int] of var opt int: x, var opt int: y) = fzn_if_then_else_var_int(array1d(c),[deopt_int(x[i]) | i in index_set(x)],deopt_int(y)) /\ fzn_if_then_else_var_bool(array1d(c),[occurs_int(x[i]) | i in index_set(x)],occurs_int(y)); libminizinc-2.4.2/share/minizinc/std/fzn_if_then_else_var_set.mzn000066400000000000000000000006021360574160400253200ustar00rootroot00000000000000predicate fzn_if_then_else_var_set(array[int] of var bool: c, array[int] of var set of int: x, var set of int: y) = let { array[index_set(c)] of var bool: d; } in forall(i in index_set(c)) (if i > min(index_set(c)) then d[i] = (not c[i-1] /\ d[i-1]) else d[i] = true endif) /\ forall (i in index_set(c)) (c[i] /\ d[i] -> y=x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_increasing_bool.mzn000066400000000000000000000005661360574160400243170ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in increasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate fzn_increasing_bool(array[int] of var bool: x) = forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] <= x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_increasing_bool_reif.mzn000066400000000000000000000006161360574160400253200ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in increasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate fzn_increasing_bool_reif(array[int] of var bool: x, var bool: b) = b <-> forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] <= x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_increasing_float.mzn000066400000000000000000000005701360574160400244640ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in increasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate fzn_increasing_float(array[int] of var float: x) = forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] <= x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_increasing_float_reif.mzn000066400000000000000000000006201360574160400254650ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in increasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate fzn_increasing_float_reif(array[int] of var float: x, var bool: b) = b <-> forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] <= x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_increasing_int.mzn000066400000000000000000000005641360574160400241540ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in increasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate fzn_increasing_int(array[int] of var int: x) = forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] <= x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_increasing_int_reif.mzn000066400000000000000000000006141360574160400251550ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in increasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate fzn_increasing_int_reif(array[int] of var int: x, var bool: b) = b <-> forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] <= x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_increasing_set.mzn000066400000000000000000000005731360574160400241550ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in increasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate fzn_increasing_set(array[int] of var set of int: x) = forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] <= x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_increasing_set_reif.mzn000066400000000000000000000006231360574160400251560ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in increasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate fzn_increasing_set_reif(array[int] of var set of int: x, var bool: b) = b <-> forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] <= x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_int_set_channel.mzn000066400000000000000000000006051360574160400243110ustar00rootroot00000000000000predicate fzn_int_set_channel(array[int] of var int: x, array[int] of var set of int: y) = forall(i in index_set(x)) (x[i] in index_set(y)) /\ forall(j in index_set(y)) (y[j] subset index_set(x)) /\ forall(i in index_set(x), j in index_set(y)) (x[i] = j <-> i in y[j]); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_int_set_channel_reif.mzn000066400000000000000000000007331360574160400253200ustar00rootroot00000000000000predicate fzn_int_set_channel_reif(array[int] of var int: x, array[int] of var set of int: y, var bool: b) = b <-> ( forall(i in index_set(x)) (x[i] in index_set(y)) /\ forall(j in index_set(y)) (y[j] subset index_set(x)) /\ forall(i in index_set(x), j in index_set(y)) (x[i] = j <-> i in y[j]) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_inverse.mzn000066400000000000000000000004111360574160400226220ustar00rootroot00000000000000predicate fzn_inverse(array[int] of var int: f, array[int] of var int: invf) = forall(i in index_set(f), j in index_set(invf)) ( f[i] in index_set(invf) /\ invf[j] in index_set(f) /\ (j == f[i] <-> i == invf[j]) ); libminizinc-2.4.2/share/minizinc/std/fzn_inverse_reif.mzn000066400000000000000000000005051360574160400236330ustar00rootroot00000000000000predicate fzn_inverse_reif(array[int] of var int: f, array[int] of var int: invf, var bool: b) = b <-> forall(i in index_set(f), j in index_set(invf)) ( f[i] in index_set(invf) /\ invf[j] in index_set(f) /\ (j == f[i] <-> i == invf[j]) ); libminizinc-2.4.2/share/minizinc/std/fzn_inverse_set.mzn000066400000000000000000000005711360574160400235040ustar00rootroot00000000000000predicate fzn_inverse_set(array[int] of var set of int: f, array[int] of var set of int: invf) = forall(i in index_set(f)) ( f[i] subset index_set(invf) ) /\ forall(j in index_set(invf)) ( invf[j] subset index_set(f) ) /\ forall(i in index_set(f), j in index_set(invf)) ( (j in f[i] <-> i in invf[j]) ); libminizinc-2.4.2/share/minizinc/std/fzn_inverse_set_reif.mzn000066400000000000000000000007271360574160400245140ustar00rootroot00000000000000predicate fzn_inverse_set_reif(array[int] of var set of int: f, array[int] of var set of int: invf, var bool: b) = b <-> ( forall(i in index_set(f)) ( f[i] subset index_set(invf) ) /\ forall(j in index_set(invf)) ( invf[j] subset index_set(f) ) /\ forall(i in index_set(f), j in index_set(invf)) ( (j in f[i] <-> i in invf[j]) ) ); libminizinc-2.4.2/share/minizinc/std/fzn_knapsack.mzn000066400000000000000000000004561360574160400227530ustar00rootroot00000000000000predicate fzn_knapsack(array[int] of int: w, array[int] of int:p, array[int] of var int:x, var int: W, var int: P) = forall (i in index_set(x)) (x[i] >= 0) /\ W >= 0 /\ P >= 0 /\ P = sum(i in index_set(p)) (x[i]*p[i]) /\ W = sum(i in index_set(w)) (x[i]*w[i]); libminizinc-2.4.2/share/minizinc/std/fzn_knapsack_reif.mzn000066400000000000000000000005371360574160400237600ustar00rootroot00000000000000predicate fzn_knapsack_reif(array[int] of int: w, array[int] of int:p, array[int] of var int:x, var int: W, var int: P, var bool: b) = b <-> ( forall (i in index_set(x)) (x[i] >= 0) /\ W >= 0 /\ P >= 0 /\ P = sum(i in index_set(p)) (x[i]*p[i]) /\ W = sum(i in index_set(w)) (x[i]*w[i]) ); libminizinc-2.4.2/share/minizinc/std/fzn_lex2.mzn000066400000000000000000000012371360574160400220300ustar00rootroot00000000000000include "lex_lesseq.mzn"; predicate fzn_lex2(array[int, int] of var int: x) = let { int: lbx1 = min(index_set_1of2(x)), int: ubx1 = max(index_set_1of2(x)), int: lbx2 = min(index_set_2of2(x)), int: ubx2 = max(index_set_2of2(x)) } in ( forall(i in lbx1 + 1 .. ubx1) ( lex_lesseq([x[i - 1, j] | j in index_set_2of2(x)], [x[i, j] | j in index_set_2of2(x)] ) ) /\ forall(j in lbx2 + 1 .. ubx2) ( lex_lesseq([x[i, j - 1] | i in index_set_1of2(x)], [x[i, j ] | i in index_set_1of2(x)] ) ) ); libminizinc-2.4.2/share/minizinc/std/fzn_lex2_reif.mzn000066400000000000000000000012671360574160400230400ustar00rootroot00000000000000include "lex_lesseq.mzn"; predicate fzn_lex2_reif(array[int, int] of var int: x, var bool: b) = let { int: lbx1 = min(index_set_1of2(x)), int: ubx1 = max(index_set_1of2(x)), int: lbx2 = min(index_set_2of2(x)), int: ubx2 = max(index_set_2of2(x)) } in b <-> ( forall(i in lbx1 + 1 .. ubx1) ( lex_lesseq([x[i - 1, j] | j in index_set_2of2(x)], [x[i, j] | j in index_set_2of2(x)] ) ) /\ forall(j in lbx2 + 1 .. ubx2) ( lex_lesseq([x[i, j - 1] | i in index_set_1of2(x)], [x[i, j ] | i in index_set_1of2(x)] ) ) ); libminizinc-2.4.2/share/minizinc/std/fzn_lex_less_bool.mzn000066400000000000000000000017011360574160400240030ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is strictly lexicographically less than array 'y'. % Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate fzn_lex_less_bool(array[int] of var bool: x, array[int] of var bool: y) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = min(ux - lx, uy - ly), array[0..size+1] of var bool: b } in b[0] /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx < uy - ly); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_lex_less_bool_reif.mzn000066400000000000000000000020011360574160400250020ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is strictly lexicographically less than array 'y'. % Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate fzn_lex_less_bool_reif(array[int] of var bool: x, array[int] of var bool: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = min(ux - lx, uy - ly), array[0..size+1] of var bool: b } in (c <-> b[0]) /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx < uy - ly); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_lex_less_float.mzn000066400000000000000000000017051360574160400241610ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is strictly lexicographically less than array 'y'. % Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate fzn_lex_less_float(array[int] of var float: x, array[int] of var float: y) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = min(ux - lx, uy - ly), array[0..size+1] of var bool: b } in b[0] /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx < uy - ly); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_lex_less_float_reif.mzn000066400000000000000000000020061360574160400251610ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is strictly lexicographically less than array 'y'. % Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate fzn_lex_less_float_reif(array[int] of var float: x, array[int] of var float: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = min(ux - lx, uy - ly), array[0..size+1] of var bool: b } in (c <-> b[0]) /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx < uy - ly); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_lex_less_int.mzn000066400000000000000000000016751360574160400236540ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is strictly lexicographically less than array 'y'. % Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate fzn_lex_less_int(array[int] of var int: x, array[int] of var int: y) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = min(ux - lx, uy - ly), array[0..size+1] of var bool: b } in b[0] /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx < uy - ly); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_lex_less_int_reif.mzn000066400000000000000000000017741360574160400246610ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is strictly lexicographically less than array 'y'. % Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate fzn_lex_less_int_reif(array[int] of var int: x, array[int] of var int: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = min(ux - lx, uy - ly), array[0..size+1] of var bool: b } in (c <-> b[0]) /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx < uy - ly); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_lex_less_set.mzn000066400000000000000000000017131360574160400236460ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is strictly lexicographically less than array 'y'. % Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate fzn_lex_less_set(array[int] of var set of int: x, array[int] of var set of int: y) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = min(ux - lx, uy - ly), array[0..size+1] of var bool: b } in b[0] /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx < uy - ly); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_lex_less_set_reif.mzn000066400000000000000000000020121360574160400246440ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is strictly lexicographically less than array 'y'. % Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate fzn_lex_less_set_reif(array[int] of var set of int: x, array[int] of var set of int: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = min(ux - lx, uy - ly), array[0..size+1] of var bool: b } in (c <-> b[0]) /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx < uy - ly); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_lex_lesseq_bool.mzn000066400000000000000000000017121360574160400243330ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is lexicographically less than or equal to % array 'y'. Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate fzn_lex_lesseq_bool(array[int] of var bool: x, array[int] of var bool: y) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = min(ux - lx, uy - ly), array[0..size+1] of var bool: b } in b[0] /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx <= uy - ly); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_lex_lesseq_bool_reif.mzn000066400000000000000000000020141360574160400253340ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is lexicographically less than or equal to % array 'y'. Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate fzn_lex_lesseq_bool_reif(array[int] of var bool: x, array[int] of var bool: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = min(ux - lx, uy - ly), array[0..size+1] of var bool: b } in (c <-> b[0]) /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx <= uy - ly); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_lex_lesseq_float.mzn000066400000000000000000000020631360574160400245050ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is lexicographically less than or equal to % array 'y'. Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate fzn_lex_lesseq_float(array[int] of var float: x, array[int] of var float: y) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = min(ux - lx, uy - ly), array[0..size+1] of var bool: b } % b[i] is true if the lexicographical order holds from position i on. in b[0] /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx <= uy - ly) ; %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_lex_lesseq_float_reif.mzn000066400000000000000000000021661360574160400255160ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is lexicographically less than or equal to % array 'y'. Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate fzn_lex_lesseq_float_reif(array[int] of var float: x, array[int] of var float: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = min(ux - lx, uy - ly), array[0..size+1] of var bool: b } % b[i] is true if the lexicographical order holds from position i on. in (c <-> b[0]) /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx <= uy - ly) ; %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_lex_lesseq_int.mzn000066400000000000000000000020471360574160400241740ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is lexicographically less than or equal to % array 'y'. Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate fzn_lex_lesseq_int(array[int] of var int: x, array[int] of var int: y) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = min(ux - lx, uy - ly), array[0..size+1] of var bool: b } % b[i] is true if the lexicographical order holds from position i on. in b[0] /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx <= uy - ly) ; %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_lex_lesseq_int_reif.mzn000066400000000000000000000021451360574160400252000ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is lexicographically less than or equal to % array 'y'. Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate fzn_lex_lesseq_int_reif(array[int] of var int: x, array[int] of var int: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = min(ux - lx, uy - ly), array[0..size+1] of var bool: b } % b[i] is true if the lexicographical order holds from position i on. in (c <-> b[0]) /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx <= uy - ly) ; %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_lex_lesseq_set.mzn000066400000000000000000000020711360574160400241720ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is lexicographically less than or equal to % array 'y'. Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate fzn_lex_lesseq_set(array[int] of var set of int: x, array[int] of var set of int: y) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = min(ux - lx, uy - ly), array[0..size+1] of var bool: b } % b[i] is true if the lexicographical order holds from position i on. in b[0] /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx <= uy - ly) ; %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_lex_lesseq_set_reif.mzn000066400000000000000000000021721360574160400252010ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is lexicographically less than or equal to % array 'y'. Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate fzn_lex_lesseq_set_reif(array[int] of var set of int: x, array[int] of var set of int: y, var bool: c) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), int: size = min(ux - lx, uy - ly), array[0..size+1] of var bool: b } % b[i] is true if the lexicographical order holds from position i on. in (c <-> b[0]) /\ forall(i in 0..size) ( b[i] = ( x[lx + i] <= y[ly + i] /\ (x[lx + i] < y[ly + i] \/ b[i+1]) ) ) /\ b[size + 1] = (ux - lx <= uy - ly) ; %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_link_set_to_booleans.mzn000066400000000000000000000002061360574160400253450ustar00rootroot00000000000000predicate fzn_link_set_to_booleans(var set of int: s, array[int] of var bool: b) = forall(i in index_set(b)) ( b[i] <-> i in s ); libminizinc-2.4.2/share/minizinc/std/fzn_link_set_to_booleans_reif.mzn000066400000000000000000000002401360574160400263500ustar00rootroot00000000000000predicate fzn_link_set_to_booleans_reif(var set of int: s, array[int] of var bool: b, var bool: bb) = bb <-> forall(i in index_set(b)) ( b[i] <-> i in s ); libminizinc-2.4.2/share/minizinc/std/fzn_mdd.mzn000066400000000000000000000035631360574160400217260ustar00rootroot00000000000000predicate fzn_mdd(array[int] of var int: x, % variables constrained by MDD int: N, % number of nodes root is node 1 array[int] of int: level, % level of each node root is level 1, T is level length(x)+1 int: E, % number of edges array[int] of int: from, % edge leaving node 1..N array[int] of set of int: label, % value of variable array[int] of int: to % edge entering node 0..N where 0 = T node ) = let { set of int: NODE = 1..N; set of int: EDGE = 1..E; int: L = length(x); array[0..N] of var bool: bn; array[EDGE] of var bool: be; set of int: D = dom_array(x); } in bn[0] /\ % true node is true bn[1] /\ % root must hold % T1 each node except the true node enforces an outgoing edge forall(n in NODE)(bn[n] -> exists(e in EDGE where from[e] = n)(be[e])) /\ % T23 each edge enforces its endpoints forall(e in EDGE)((be[e] -> bn[from[e]]) /\ (be[e] -> bn[to[e]])) /\ % T4 each edge enforces its label forall(e in EDGE)(be[e] -> x[level[from[e]]] in label[e]) /\ % P1 each node enforces its outgoing edges forall(e in EDGE)(bn[from[e]] /\ x[level[from[e]]] in label[e] -> be[e]) /\ % P2 each node except the root enforces an incoming edge exists(e in EDGE where to[e] = 0)(be[e]) /\ forall(n in 2..N)(bn[n] -> exists(e in EDGE where to[e] = n)(be[e])) /\ % P3 each label has a support forall(i in 1..L, d in D) (x[i] = d -> exists(e in EDGE where level[from[e]] = i /\ d in label[e])(be[e])) /\ % P4 exactly one node at each level forall(i in 1..L) (sum(n in NODE where level[n] = i)(bn[n]) = 1); libminizinc-2.4.2/share/minizinc/std/fzn_mdd_nondet.mzn000066400000000000000000000031501360574160400232650ustar00rootroot00000000000000predicate fzn_mdd_nondet(array[int] of var int: x, % variables constrained by MDD int: N, % number of nodes root is node 1 array[int] of int: level, % level of each node root is level 1, T is level length(x)+1 int: E, % number of edges array[int] of int: from, % edge leaving node 1..N array[int] of set of int: label, % value of variable array[int] of int: to % edge entering node 0..N where 0 = T node ) = let { set of int: NODE = 1..N; set of int: EDGE = 1..E; int: L = length(x); array[0..N] of var bool: bn; array[EDGE] of var bool: be; set of int: D = dom_array(x); } in bn[0] /\ % true node is true bn[1] /\ % root must hold % T1 each node except the root enforces an outgoing edge forall(n in NODE)(bn[n] -> exists(e in EDGE where from[e] = n)(be[e])) /\ % T23 each edge enforces its endpoints forall(e in EDGE)((be[e] -> bn[from[e]]) /\ (be[e] -> bn[to[e]])) /\ % T4 each edge enforces its label forall(e in EDGE)(be[e] -> x[level[from[e]]] in label[e]) /\ % P2 each node except the root enforces an incoming edge exists(e in EDGE where to[e] = 0)(be[e]) /\ forall(n in 2..N)(bn[n] -> exists(e in EDGE where to[e] = n)(be[e])) /\ % P3 each label has a support forall(i in 1..L, d in D) (x[i] = d -> exists(e in EDGE where level[from[e]] = i /\ d in label[e])(be[e])); libminizinc-2.4.2/share/minizinc/std/fzn_mdd_nondet_reif.mzn000066400000000000000000000032761360574160400243030ustar00rootroot00000000000000predicate fzn_mdd_nondet_reif(array[int] of var int: x, % variables constrained by MDD int: N, % number of nodes root is node 1 array[int] of int: level, % level of each node root is level 1, T is level length(x)+1 int: E, % number of edges array[int] of int: from, % edge leaving node 1..N array[int] of set of int: label, % value of variable array[int] of int: to, % edge entering node 0..N where 0 = T node var bool: b % reification value ) = let { set of int: NODE = 1..N; set of int: EDGE = 1..E; int: L = length(x); array[0..N] of var bool: bn; array[EDGE] of var bool: be; set of int: D = dom_array(x); } in bn[0] /\ % true node is true (b <-> bn[1]) /\ % root gives truth value % T1 each node except the root enforces an outgoing edge forall(n in NODE)(bn[n] -> exists(e in EDGE where from[e] = n)(be[e])) /\ % T23 each edge enforces its endpoints forall(e in EDGE)((be[e] -> bn[from[e]]) /\ (be[e] -> bn[to[e]])) /\ % T4 each edge enforces its label forall(e in EDGE)(be[e] -> x[level[from[e]]] in label[e]) /\ % P2 each node except the root enforces an incoming edge exists(e in EDGE where to[e] = 0)(be[e]) /\ forall(n in 2..N)(bn[n] -> exists(e in EDGE where to[e] = n)(be[e])) /\ % P3 each label has a support forall(i in 1..L, d in D) (x[i] = d -> exists(e in EDGE where level[from[e]] = i /\ d in label[e])(be[e])); libminizinc-2.4.2/share/minizinc/std/fzn_mdd_reif.mzn000066400000000000000000000046241360574160400227320ustar00rootroot00000000000000predicate fzn_mdd_reif(array[int] of var int: x, % variables constrained by MDD int: N, % number of nodes root is node 1 array[int] of int: level, % level of each node root is level 1, T is level length(x)+1 int: E, % number of edges array[int] of int: from, % edge leaving node 1..N array[int] of set of int: label, % value of variable array[int] of int: to, % edge entering node 0..N where 0 = T node var bool: b % reification value ) = let { set of int: NODE = 1..N; set of int: EDGE = 1..E; int: L = length(x); array[0..N] of var bool: bn; array[EDGE] of var bool: be; set of int: D = dom_array(x); } in (b <-> bn[0]) /\ % true node is result bn[1] /\ % root is always true % T1 each node except the true enforces an outgoing edge forall(n in NODE)(bn[n] -> (exists(e in EDGE where from[e] = n)(be[e]) \/ b = 0)) /\ % T23 each edge enforces its endpoints forall(e in EDGE)((be[e] -> bn[from[e]]) /\ (be[e] -> bn[to[e]])) /\ % T4 each edge enforces its label forall(e in EDGE)(be[e] -> x[level[from[e]]] in label[e]) /\ % P1 each node enforces its outgoing edges forall(e in EDGE)(bn[from[e]] /\ x[level[from[e]]] in label[e] -> be[e]) /\ % P2 each node except the root enforces an incoming edge (bn[0] -> exists(e in EDGE where to[e] = 0)(be[e])) /\ forall(n in 2..N)(bn[n] -> exists(e in EDGE where to[e] = n)(be[e])) /\ % P3 each label has a support, either an edge or to give false forall(i in 1..L, d in D) (x[i] = d -> forall(n in NODE where level[n] = i, e in EDGE where from[e] = n /\ d in label[e]) (bn[n] -> be[e]) /\ forall(n in NODE where level[n] = i /\ not exists(e in EDGE where from[e] = n) (d in label[e])) (bn[n] -> b = 0)) /\ % P4 at most one node at every level is true (redundant) forall(i in 1..L) (sum(n in NODE where level[n] = i)(bn[n]) <= 1); libminizinc-2.4.2/share/minizinc/std/fzn_member_bool.mzn000066400000000000000000000005061360574160400234360ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array or set 'x'. %-----------------------------------------------------------------------------% predicate fzn_member_bool(array[int] of var bool: x, var bool: y) = exists(i in index_set(x)) ( x[i] == y ); libminizinc-2.4.2/share/minizinc/std/fzn_member_bool_reif.mzn000066400000000000000000000005361360574160400244460ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array or set 'x'. %-----------------------------------------------------------------------------% predicate fzn_member_bool_reif(array[int] of var bool: x, var bool: y, var bool: b) = b <-> exists(i in index_set(x)) ( x[i] == y ); libminizinc-2.4.2/share/minizinc/std/fzn_member_float.mzn000066400000000000000000000005111360574160400236040ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array or set 'x'. %-----------------------------------------------------------------------------% predicate fzn_member_float(array[int] of var float: x, var float: y) = exists(i in index_set(x)) ( x[i] == y ); libminizinc-2.4.2/share/minizinc/std/fzn_member_float_reif.mzn000066400000000000000000000005411360574160400246140ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array or set 'x'. %-----------------------------------------------------------------------------% predicate fzn_member_float_reif(array[int] of var float: x, var float: y, var bool: b) = b <-> exists(i in index_set(x)) ( x[i] == y ); libminizinc-2.4.2/share/minizinc/std/fzn_member_int.mzn000066400000000000000000000005031360574160400232720ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array or set 'x'. %-----------------------------------------------------------------------------% predicate fzn_member_int(array[int] of var int: x, var int: y) = exists(i in index_set(x)) ( x[i] == y ); libminizinc-2.4.2/share/minizinc/std/fzn_member_int_reif.mzn000066400000000000000000000005331360574160400243020ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array or set 'x'. %-----------------------------------------------------------------------------% predicate fzn_member_int_reif(array[int] of var int: x, var int: y, var bool: b) = b <-> exists(i in index_set(x)) ( x[i] == y ); libminizinc-2.4.2/share/minizinc/std/fzn_member_set.mzn000066400000000000000000000005211360574160400232730ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array of set 'x'. %-----------------------------------------------------------------------------% predicate fzn_member_set(array[int] of var set of int: x, var set of int: y) = exists(i in index_set(x)) ( x[i] == y ); libminizinc-2.4.2/share/minizinc/std/fzn_member_set_reif.mzn000066400000000000000000000005511360574160400243030ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array of set 'x'. %-----------------------------------------------------------------------------% predicate fzn_member_set_reif(array[int] of var set of int: x, var set of int: y, var bool: b) = b <-> exists(i in index_set(x)) ( x[i] == y ); libminizinc-2.4.2/share/minizinc/std/fzn_network_flow.mzn000066400000000000000000000010051360574160400236670ustar00rootroot00000000000000predicate fzn_network_flow(array[int,1..2] of int: arc, array[int] of int: balance, array[int] of var int: flow) = let { int: source_node = 1; int: sink_node = 2; set of int: ARCS = index_set_1of2(arc); set of int: NODES = index_set(balance); } in forall (i in NODES) ( sum (j in ARCS where i == arc[j,source_node]) (flow[j]) - sum (j in ARCS where i == arc[j,sink_node]) (flow[j]) = balance[i] ); libminizinc-2.4.2/share/minizinc/std/fzn_network_flow_cost.mzn000066400000000000000000000011341360574160400247220ustar00rootroot00000000000000predicate fzn_network_flow_cost(array[int,1..2] of int: arc, array[int] of int: balance, array[int] of int: weight, array[int] of var int: flow, var int: cost) = let { int: source_node = 1; int: sink_node = 2; set of int: ARCS = index_set_1of2(arc); set of int: NODES = index_set(balance); } in cost = sum(i in ARCS) (flow[i] * weight[i]) /\ forall (i in NODES) ( sum (j in ARCS where i == arc[j,source_node]) (flow[j]) - sum (j in ARCS where i == arc[j,sink_node]) (flow[j]) = balance[i] ); libminizinc-2.4.2/share/minizinc/std/fzn_network_flow_cost_reif.mzn000066400000000000000000000012271360574160400257320ustar00rootroot00000000000000predicate fzn_network_flow_cost_reif(array[int,1..2] of int: arc, array[int] of int: balance, array[int] of int: weight, array[int] of var int: flow, var int: cost, var bool: b) = let { int: source_node = 1; int: sink_node = 2; set of int: ARCS = index_set_1of2(arc); set of int: NODES = index_set(balance); } in b <-> ( cost = sum(i in ARCS) (flow[i] * weight[i]) /\ forall (i in NODES) ( sum (j in ARCS where i == arc[j,source_node]) (flow[j]) - sum (j in ARCS where i == arc[j,sink_node]) (flow[j]) = balance[i] ) ); libminizinc-2.4.2/share/minizinc/std/fzn_network_flow_reif.mzn000066400000000000000000000010641360574160400247010ustar00rootroot00000000000000predicate fzn_network_flow_reif(array[int,1..2] of int: arc, array[int] of int: balance, array[int] of var int: flow, var bool: b) = let { int: source_node = 1; int: sink_node = 2; set of int: ARCS = index_set_1of2(arc); set of int: NODES = index_set(balance); } in b <-> forall (i in NODES) ( sum (j in ARCS where i == arc[j,source_node]) (flow[j]) - sum (j in ARCS where i == arc[j,sink_node]) (flow[j]) = balance[i] ); libminizinc-2.4.2/share/minizinc/std/fzn_neural_net.mzn000066400000000000000000000053061360574160400233130ustar00rootroot00000000000000predicate fzn_neural_net(array[int] of var float: inputs, array[int] of int: input_ids, array[int] of var float: outputs, array[int] of int: output_ids, array[int] of float: bias, array[int] of float: edge_weight, array[int] of int: edge_parent, array[int] of int: first_edge, NEURON_TYPE: neuron_type) = let { set of int: NODE = index_set(bias) } in let { set of int: INPUTS = array2set(input_ids) } in let { set of int: EDGE = index_set(edge_weight) } in let { array[NODE] of var float: neuron } in forall(i in index_set(inputs))(neuron[input_ids[i]] = inputs[i]) /\ forall(i in index_set(outputs))(neuron[output_ids[i]] = outputs[i]) /\ forall(i in NODE diff INPUTS) ( let { int: first = first_edge[i]; int: last = if i = max(NODE) then max(index_set(first_edge)) else first_edge[i+1] - 1 endif; array[int] of var float: ins = [neuron[edge_parent[j]] | j in first..last]; array[int] of float: ws = [ edge_weight[j] | j in first..last ]; float: b = bias[i]; } in neuron[i] = if neuron_type = NT_RELU then neuron_relu(ins,ws,b) elseif neuron_type = NT_STEP then neuron_step(ins,ws,b) elseif neuron_type = NT_LINEAR then neuron_linear(ins,ws,b) elseif neuron_type = NT_SOFTPLUS then neuron_softplus(ins,ws,b) else 0.0 endif ); %-----------------------------------------------------------------------------% function var float: neuron_relu(array[int] of var float: inputs, array[int] of float: weights, float: bias) = max(0.0, sum(i in index_set(inputs))(weights[i]*inputs[i]) + bias); function var float: neuron_step(array[int] of var float: inputs, array[int] of float: weights, float: bias) = (sum(i in index_set(inputs))(weights[i]*inputs[i]) + bias >= 0.0); function var float: neuron_linear(array[int] of var float: inputs, array[int] of float: weights, float: bias) = (sum(i in index_set(inputs))(weights[i]*inputs[i]) + bias); function var float: neuron_softplus(array[int] of var float: inputs, array[int] of float: weights, float: bias) = (ln(1 + exp(sum(i in index_set(inputs))(weights[i]*inputs[i]) + bias))); libminizinc-2.4.2/share/minizinc/std/fzn_neural_net_reif.mzn000066400000000000000000000011311360574160400243100ustar00rootroot00000000000000predicate fzn_neural_net_reif(array[int] of var float: inputs, array[int] of int: input_ids, array[int] of var float: outputs, array[int] of int: output_ids, array[int] of float: bias, array[int] of float: edge_weight, array[int] of int: edge_parent, array[int] of int: first_edge, NEURON_TYPE: neuron_type, var bool: b) = abort("Reification of neural_net constraint is not supported"); libminizinc-2.4.2/share/minizinc/std/fzn_nvalue.mzn000066400000000000000000000003601360574160400224440ustar00rootroot00000000000000predicate fzn_nvalue(var int: n, array[int] of var int: x) = let { int: lx = lb_array(x), int: ux = ub_array(x), } in n == sum(j in lx..ux) ( bool2int(exists(i in index_set(x)) ( x[i] = j )) ); libminizinc-2.4.2/share/minizinc/std/fzn_nvalue_reif.mzn000066400000000000000000000004101360574160400234450ustar00rootroot00000000000000predicate fzn_nvalue_reif(var int: n, array[int] of var int: x, var bool: b) = let { int: lx = lb_array(x), int: ux = ub_array(x), } in b <-> n == sum(j in lx..ux) ( bool2int(exists(i in index_set(x)) ( x[i] = j )) ); libminizinc-2.4.2/share/minizinc/std/fzn_partition_set.mzn000066400000000000000000000003331360574160400240360ustar00rootroot00000000000000include "all_disjoint.mzn"; predicate fzn_partition_set(array[int] of var set of int: S, set of int: universe) = all_disjoint(S) /\ universe == array_union(i in index_set(S)) ( S[i] ); libminizinc-2.4.2/share/minizinc/std/fzn_partition_set_reif.mzn000066400000000000000000000004341360574160400250450ustar00rootroot00000000000000include "all_disjoint.mzn"; predicate fzn_partition_set_reif(array[int] of var set of int: S, set of int: universe, var bool: b) = b <-> ( all_disjoint(S) /\ universe == array_union(i in index_set(S)) ( S[i] ) ); libminizinc-2.4.2/share/minizinc/std/fzn_path_enum.mzn000066400000000000000000000014011360574160400231270ustar00rootroot00000000000000include "tree.mzn"; include "subgraph.mzn"; predicate fzn_path(array[int] of $$N: from, array[int] of $$N: to, var $$N: s, var $$N: t, array[$$N] of var bool: ns, array[int] of var bool: es) = let { int: E = length(es); array[1..2*E] of int: dfrom = from ++ to; array[1..2*E] of int: dto = to ++ from; array[1..2*E] of var bool: des; } in /* ensure that the directed edges selected agree with undirected edges */ forall(e in 1..E)(es[e-1+min(index_set(es))] <-> (des[e] \/ des[e+E])) /\ /* duplicate the edges so that the we can use directed graph path */ fzn_dpath(dfrom,dto,s,t,ns,des); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_path_enum_reif.mzn000066400000000000000000000006141360574160400241410ustar00rootroot00000000000000include "tree.mzn"; include "subgraph.mzn"; predicate fzn_path_reif(array[int] of $$N: from, array[int] of $$N: to, var $$N: s, var $$N: t, array[$$N] of var bool: ns, array[int] of var bool: es, var bool: b) = abort("Reified path constraint is not supported"); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_path_int.mzn000066400000000000000000000013411360574160400227600ustar00rootroot00000000000000include "tree.mzn"; include "subgraph.mzn"; predicate fzn_path(int: N, int: E, array[int] of int: from, array[int] of int: to, var int: s, var int: t, array[int] of var bool: ns, array[int] of var bool: es) = let { array[1..2*E] of int: dfrom = from ++ to; array[1..2*E] of int: dto = to ++ from; array[1..2*E] of var bool: des; } in /* ensure that the directed edges selected agree with undirected edges */ forall(e in 1..E)(es[e] <-> (des[e] \/ des[e+E])) /\ /* duplicate the edges so that the we can use directed graph path */ fzn_dpath(N,2*E,dfrom,dto,s,t,ns,des); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_path_int_reif.mzn000066400000000000000000000006371360574160400237740ustar00rootroot00000000000000include "tree.mzn"; include "subgraph.mzn"; predicate fzn_path_reif(int: N, int: E, array[int] of int: from, array[int] of int: to, var int: s, var int: t, array[int] of var bool: ns, array[int] of var bool: es, var bool: b) = abort("Reified path constraint is not supported"); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_piecewise_linear.mzn000066400000000000000000000024251360574160400244650ustar00rootroot00000000000000/* * Function fzn_piecewise_linear_base creates * interval representation of x, * which is reusable if we have several pwls * on the same set of breakpoints */ function array[int, int] of var 0.0..1.0: fzn_piecewise_linear_base( var float: x, array[int] of float: xi) ::promise_total = let { set of int: is = index_set(xi), set of int: is_1 = is diff { max(is) }, array[is_1] of var 0.0..1.0: s, %% Segment variables array[is_1] of var 0..1: f, constraint 1 == sum(f), constraint forall(i in is_1)(f[i] >= s[i]), constraint x == sum(i in is_1)(xi[i] * f[i] + (xi[i+1]-xi[i]) * s[i]), } in array2d(1..2, is_1, f++s); predicate fzn_piecewise_linear(var float: x, var float: y, array[int] of float: xi, array[int] of float: vi) = let { set of int: is = index_set(xi), constraint assert(is == index_set(vi) /\ 0 x[i] in t ) /\ % All values in 't' must be mapped from a value in 's'. forall(i in ub(t)) ( i in t -> exists(j in ub(s)) ( j in s /\ x[j] == i ) ); libminizinc-2.4.2/share/minizinc/std/fzn_range_reif.mzn000066400000000000000000000007571360574160400232650ustar00rootroot00000000000000predicate fzn_range_reif(array[int] of var int: x, var set of int: s, var set of int: t, var bool: b) = b <-> ( % All values in 's' must map to a value in 't'. forall(i in ub(s)) ( i in s -> x[i] in t ) /\ % All values in 't' must be mapped from a value in 's'. forall(i in ub(t)) ( i in t -> exists(j in ub(s)) ( j in s /\ x[j] == i ) ) ); libminizinc-2.4.2/share/minizinc/std/fzn_reachable_enum.mzn000066400000000000000000000013541360574160400241100ustar00rootroot00000000000000include "subgraph.mzn"; predicate fzn_reachable(array[int] of $$N: from, array[int] of $$N: to, var $$N: r, array[$$N] of var bool: ns, array[int] of var bool: es) = let { int: E = length(es); set of int: NODE = min(index_set(ns))..max(index_set(ns)); array[1..2*E] of NODE: dfrom = from ++ to; array[1..2*E] of NODE: dto = to ++ from; array[1..2*E] of var bool: des = es ++ es; array[NODE] of var bool: dns = array1d(NODE,ns); var NODE: dr = r; } in /* duplicate the edges so that we can use directed graph reachability */ fzn_dreachable(dfrom,dto,dr,dns,des); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_reachable_enum_reif.mzn000066400000000000000000000014221360574160400251110ustar00rootroot00000000000000predicate fzn_reachable_reif(array[int] of $$N: from, array[int] of $$N: to, var $$N: r, array[$$N] of var bool: ns, array[int] of var bool: es, var bool: b) = let { int: E = length(es); set of int: NODE = min(index_set(ns))..max(index_set(ns)); array[1..2*E] of NODE: dfrom = from ++ to; array[1..2*E] of NODE: dto = to ++ from; array[1..2*E] of var bool: des = es ++ es; array[NODE] of var bool: dns = array1d(NODE,ns); var NODE: dr = r; } in /* duplicate the edges so that we can use directed graph reachability */ b <-> fzn_dreachable(dfrom,dto,dr,dns,des); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_reachable_int.mzn000066400000000000000000000011261360574160400237330ustar00rootroot00000000000000include "subgraph.mzn"; predicate fzn_reachable(int: N, int: E, array[int] of int: from, array[int] of int: to, var int: r, array[int] of var bool: ns, array[int] of var bool: es) = let { array[1..2*E] of int: dfrom = from ++ to; array[1..2*E] of int: dto = to ++ from; array[1..2*E] of var bool: des = es ++ es; } in /* duplicate the edges so that the we can use directed graph reachability */ fzn_dreachable(N,2*E,dfrom,dto,r,ns,des); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_reachable_int_reif.mzn000066400000000000000000000011631360574160400247410ustar00rootroot00000000000000predicate fzn_reachable_reif(int: N, int: E, array[int] of int: from, array[int] of int: to, var int: r, array[int] of var bool: ns, array[int] of var bool: es, var bool: b) = let { array[1..2*E] of int: dfrom = from ++ to; array[1..2*E] of int: dto = to ++ from; array[1..2*E] of var bool: des = es ++ es; } in /* duplicate the edges so that the we can use directed graph reachability */ b <-> dreachable(N,2*E,dfrom,dto,r,ns,des); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_regular.mzn000066400000000000000000000014261360574160400226170ustar00rootroot00000000000000predicate fzn_regular(array[int] of var int: x, int: Q, int: S, array[int,int] of int: d, int: q0, set of int: F) = let { % If x has index set m..n-1, then a[m] holds the initial state % (q0), and a[i+1] holds the state we're in after processing % x[i]. If a[n] is in F, then we succeed (ie. accept the string). int: m = min(index_set(x)), int: n = max(index_set(x)) + 1, array[m..n] of var 1..Q: a } in a[m] = q0 /\ % Set a[0]. forall(i in index_set(x)) ( x[i] in 1..S /\ % Do this in case it's a var. a[i+1] = d[a[i], x[i]] % Determine a[i+1]. ) /\ a[n] in F; % Check the final state is in F. libminizinc-2.4.2/share/minizinc/std/fzn_regular_nfa.mzn000066400000000000000000000014451360574160400234440ustar00rootroot00000000000000predicate fzn_regular_nfa(array[int] of var int: x, int: Q, int: S, array[int,int] of set of int: d, int: q0, set of int: F) = let { % If x has index set m..n-1, then a[m] holds the initial state % (q0), and a[i+1] holds the state we're in after processing % x[i]. If a[n] is in F, then we succeed (ie. accept the string). int: m = min(index_set(x)), int: n = max(index_set(x)) + 1, array[m..n] of var 1..Q: a } in a[m] = q0 /\ % Set a[0]. forall(i in index_set(x)) ( x[i] in 1..S /\ % Do this in case it's a var. a[i+1] in d[a[i], x[i]] % Determine a[i+1]. ) /\ a[n] in F; % Check the final state is in F. libminizinc-2.4.2/share/minizinc/std/fzn_regular_nfa_reif.mzn000066400000000000000000000004131360574160400244430ustar00rootroot00000000000000predicate fzn_regular_nfa_reif(array[int] of var int: x, int: Q, int: S, array[int,int] of set of int: d, int: q0, set of int: F, var bool: b) = abort("Reified regular_nfa constraint is not supported"); libminizinc-2.4.2/share/minizinc/std/fzn_regular_nfa_set.mzn000066400000000000000000000014541360574160400243170ustar00rootroot00000000000000predicate fzn_regular_nfa(array[int] of var int: x, int: Q, set of int: S, array[int,int] of set of int: d, int: q0, set of int: F) = let { % If x has index set m..n-1, then a[m] holds the initial state % (q0), and a[i+1] holds the state we're in after processing % x[i]. If a[n] is in F, then we succeed (ie. accept the string). int: m = min(index_set(x)), int: n = max(index_set(x)) + 1, array[m..n] of var 1..Q: a } in a[m] = q0 /\ % Set a[0]. forall(i in index_set(x)) ( x[i] in S /\ % Do this in case it's a var. a[i+1] in d[a[i], x[i]] % Determine a[i+1]. ) /\ a[n] in F; % Check the final state is in F. libminizinc-2.4.2/share/minizinc/std/fzn_regular_nfa_set_reif.mzn000066400000000000000000000004221360574160400253160ustar00rootroot00000000000000predicate fzn_regular_nfa_reif(array[int] of var int: x, int: Q, set of int: S, array[int,int] of set of int: d, int: q0, set of int: F, var bool: b) = abort("Reified regular_nfa constraint is not supported"); libminizinc-2.4.2/share/minizinc/std/fzn_regular_regexp.mzn000066400000000000000000000000741360574160400241670ustar00rootroot00000000000000predicate fzn_regular(array[int] of var int: x, string: r); libminizinc-2.4.2/share/minizinc/std/fzn_regular_reif.mzn000066400000000000000000000003641360574160400236240ustar00rootroot00000000000000predicate fzn_regular_reif(array[int] of var int: x, int: Q, int: S, array[int,int] of int: d, int: q0, set of int: F, var bool: b) = abort("Reified regular constraint is not supported"); libminizinc-2.4.2/share/minizinc/std/fzn_regular_set.mzn000066400000000000000000000014351360574160400234720ustar00rootroot00000000000000predicate fzn_regular(array[int] of var int: x, int: Q, set of int: S, array[int,int] of int: d, int: q0, set of int: F) = let { % If x has index set m..n-1, then a[m] holds the initial state % (q0), and a[i+1] holds the state we're in after processing % x[i]. If a[n] is in F, then we succeed (ie. accept the string). int: m = min(index_set(x)), int: n = max(index_set(x)) + 1, array[m..n] of var 1..Q: a } in a[m] = q0 /\ % Set a[0]. forall(i in index_set(x)) ( x[i] in S /\ % Do this in case it's a var. a[i+1] = d[a[i], x[i]] % Determine a[i+1]. ) /\ a[n] in F; % Check the final state is in F. libminizinc-2.4.2/share/minizinc/std/fzn_regular_set_reif.mzn000066400000000000000000000003731360574160400244770ustar00rootroot00000000000000predicate fzn_regular_reif(array[int] of var int: x, int: Q, set of int: S, array[int,int] of int: d, int: q0, set of int: F, var bool: b) = abort("Reified regular constraint is not supported"); libminizinc-2.4.2/share/minizinc/std/fzn_roots.mzn000066400000000000000000000004761360574160400223300ustar00rootroot00000000000000predicate fzn_roots(array[int] of var int: x, var set of int: s, var set of int: t) = % All values in 's' must map to a value in 't'. forall(i in ub(s)) ( i in s -> x[i] in t ) /\ forall(i in ub(t)) ( i in t -> forall(j in index_set(x)) (x[j] = i -> j in s ) ); libminizinc-2.4.2/share/minizinc/std/fzn_roots_reif.mzn000066400000000000000000000005651360574160400233340ustar00rootroot00000000000000predicate fzn_roots_reif(array[int] of var int: x, var set of int: s, var set of int: t, var bool: b) = b <-> ( % All values in 's' must map to a value in 't'. forall(i in ub(s)) ( i in s -> x[i] in t ) /\ forall(i in ub(t)) ( i in t -> forall(j in index_set(x)) (x[j] = i -> j in s ) ) ); libminizinc-2.4.2/share/minizinc/std/fzn_seq_precede_chain_int.mzn000066400000000000000000000007101360574160400254440ustar00rootroot00000000000000predicate fzn_seq_precede_chain_int(array[int] of var int: X) = let { int : l = lb_array (X) ; % least possible value int : u = ub_array (X) ; % greatest possible value int : f = min ( index_set (X )); array [ index_set (X) ] of var l .. u: H; } in H[f] <= 1 /\ H[f] = max (X[f], 0) /\ forall ( i in index_set ( X) diff {f} ) ( H[i] <= H[i-1] + 1 /\ H[i] = max (X[i], H[i-1]) ); libminizinc-2.4.2/share/minizinc/std/fzn_seq_precede_chain_int_reif.mzn000066400000000000000000000002241360574160400264510ustar00rootroot00000000000000predicate fzn_seq_precede_chain_int_reif(array[int] of var int: X, var bool: b) = abort("Reified seq_precede_chain constraint is not supported"); libminizinc-2.4.2/share/minizinc/std/fzn_seq_precede_chain_set.mzn000066400000000000000000000002331360574160400254450ustar00rootroot00000000000000predicate fzn_seq_precede_chain_set_reif(array[int] of var set of int: X, var bool: b) = abort("Reified seq_precede_chain constraint is not supported"); libminizinc-2.4.2/share/minizinc/std/fzn_seq_precede_chain_set_reif.mzn000066400000000000000000000002111360574160400264460ustar00rootroot00000000000000predicate fzn_seq_precede_chain_set(array[int] of var set of int: X) = abort("Reified seq_precede_chain constraint is not supported"); libminizinc-2.4.2/share/minizinc/std/fzn_set_member.mzn000066400000000000000000000004331360574160400232750ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array or set 'x'. %-----------------------------------------------------------------------------% predicate fzn_set_member(var set of int: x, var int: y) = y in x; libminizinc-2.4.2/share/minizinc/std/fzn_set_member_reif.mzn000066400000000000000000000004631360574160400243050ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array or set 'x'. %-----------------------------------------------------------------------------% predicate fzn_set_member_reif(var set of int: x, var int: y, var bool: b) = b <-> y in x; libminizinc-2.4.2/share/minizinc/std/fzn_sliding_sum.mzn000066400000000000000000000014011360574160400234640ustar00rootroot00000000000000predicate fzn_sliding_sum(int: low, int: up, int: seq, array[int] of var int: vs) = /* CS decomposition: see S. Brand, N. Narodytska, C-G. Quimper, P.J. Stuckey, and T. Walsh. Encodings of the sequence constraint. In C. Bessiere, editor, Proceedings of the 13th International Conference on Principles and Practice of Constraint Programming, volume 4741 of LNCS, pages 210–224. Springer-Verlag, 2007. */ let { int: lx = min(index_set(vs)); int: ux = max(index_set(vs)); array[lx-1..ux] of var int: S; } in S[lx-1] = 0 /\ forall (i in lx .. ux) ( S[i] = vs[i] + S[i-1] ) /\ forall (i in lx-1 .. ux - seq) ( S[i] <= S[i+seq] - low /\ S[i+seq] <= S[i] + up ); libminizinc-2.4.2/share/minizinc/std/fzn_sliding_sum_reif.mzn000066400000000000000000000015471360574160400245040ustar00rootroot00000000000000predicate fzn_sliding_sum_reif(int: low, int: up, int: seq, array[int] of var int: vs, var bool: b) = /* CS decomposition: see S. Brand, N. Narodytska, C-G. Quimper, P.J. Stuckey, and T. Walsh. Encodings of the sequence constraint. In C. Bessiere, editor, Proceedings of the 13th International Conference on Principles and Practice of Constraint Programming, volume 4741 of LNCS, pages 210–224. Springer-Verlag, 2007. */ let { int: lx = min(index_set(vs)); int: ux = max(index_set(vs)); array[lx-1..ux] of var int: S; } in S[lx-1] = 0 /\ forall (i in lx .. ux) ( S[i] = vs[i] + S[i-1] ) /\ b <-> forall (i in lx-1 .. ux - seq) ( S[i] <= S[i+seq] - low /\ S[i+seq] <= S[i] + up ); libminizinc-2.4.2/share/minizinc/std/fzn_sort.mzn000066400000000000000000000006711360574160400221460ustar00rootroot00000000000000include "alldifferent.mzn"; include "increasing.mzn"; predicate fzn_sort(array[int] of var int: x, array[int] of var int: y) = let { int: lx = min(index_set(x)), int: ux = max(index_set(x)), int: ly = min(index_set(y)), int: uy = max(index_set(y)), array[lx..ux] of var ly..uy: p } in forall(i in index_set(x)) ( y[p[i]] == x[i] ) /\ alldifferent(p) /\ increasing(y); libminizinc-2.4.2/share/minizinc/std/fzn_sort_reif.mzn000066400000000000000000000002611360574160400231460ustar00rootroot00000000000000include "sort_fn.mzn"; predicate fzn_sort_reif(array[int] of var int: x, array[int] of var int: y, var bool: b) = let { array[int] of var int: s = sort(x); } in b <-> s=y; libminizinc-2.4.2/share/minizinc/std/fzn_span.mzn000066400000000000000000000004731360574160400221200ustar00rootroot00000000000000predicate fzn_span(var opt int: s0, var int: d0, array[int] of var opt int: s, array[int] of var int: d) = (occurs(s0) <-> exists(i in index_set(s))(occurs(s[i]))) /\ s0 = min(s) /\ (absent(s0) -> d0 = 0) /\ s0 ~+ d0 = max([s[i] ~+ d[i] | i in index_set(s)]); libminizinc-2.4.2/share/minizinc/std/fzn_span_reif.mzn000066400000000000000000000006111360574160400231170ustar00rootroot00000000000000predicate fzn_span_reif(var opt int: s0, var int: d0, array[int] of var opt int: s, array[int] of var int: d, var bool: b) = b <-> ( (occurs(s0) <-> exists(i in index_set(s))(occurs(s[i]))) /\ s0 = min(s) /\ (absent(s0) -> d0 = 0) /\ s0 ~+ d0 = max([s[i] ~+ d[i] | i in index_set(s)]) ); libminizinc-2.4.2/share/minizinc/std/fzn_steiner.mzn000066400000000000000000000006221360574160400226240ustar00rootroot00000000000000include "tree.mzn"; predicate fzn_steiner(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of int: w, array[int] of var bool: ns, array[int] of var bool: es, var int: K) = let { var 1..N: r; } in tree(N,E,from,to,r,ns,es) /\ K = sum(e in 1..E)(es[e]*w[e]); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_steiner_reif.mzn000066400000000000000000000006061360574160400236330ustar00rootroot00000000000000predicate fzn_steiner_reif(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of int: w, array[int] of var bool: ns, array[int] of var bool: es, var int: K, var bool: b) = abort("Reified steiner constraint is not supported"); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_strict_lex2.mzn000066400000000000000000000012351360574160400234160ustar00rootroot00000000000000include "lex_less.mzn"; predicate fzn_strict_lex2(array[int, int] of var int: x) = let { int: lbx1 = min(index_set_1of2(x)), int: ubx1 = max(index_set_1of2(x)), int: lbx2 = min(index_set_2of2(x)), int: ubx2 = max(index_set_2of2(x)) } in ( forall(i in lbx1 + 1 .. ubx1) ( lex_less([x[i - 1, j] | j in index_set_2of2(x)], [x[i, j] | j in index_set_2of2(x)] ) ) /\ forall(j in lbx2 + 1 .. ubx2) ( lex_less([x[i, j - 1] | i in index_set_1of2(x)], [x[i, j ] | i in index_set_1of2(x)] ) ) ); libminizinc-2.4.2/share/minizinc/std/fzn_strict_lex2_reif.mzn000066400000000000000000000012651360574160400244260ustar00rootroot00000000000000include "lex_less.mzn"; predicate fzn_strict_lex2_reif(array[int, int] of var int: x, var bool: b) = let { int: lbx1 = min(index_set_1of2(x)), int: ubx1 = max(index_set_1of2(x)), int: lbx2 = min(index_set_2of2(x)), int: ubx2 = max(index_set_2of2(x)) } in b <-> ( forall(i in lbx1 + 1 .. ubx1) ( lex_less([x[i - 1, j] | j in index_set_2of2(x)], [x[i, j] | j in index_set_2of2(x)] ) ) /\ forall(j in lbx2 + 1 .. ubx2) ( lex_less([x[i, j - 1] | i in index_set_1of2(x)], [x[i, j ] | i in index_set_1of2(x)] ) ) ); libminizinc-2.4.2/share/minizinc/std/fzn_strictly_decreasing_bool.mzn000066400000000000000000000005531360574160400262320ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in strict decreasing order %-----------------------------------------------------------------------------% predicate fzn_strictly_decreasing_bool(array[int] of var bool: x) = forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] > x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_strictly_decreasing_bool_reif.mzn000066400000000000000000000006031360574160400272330ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in strict decreasing order %-----------------------------------------------------------------------------% predicate fzn_strictly_decreasing_bool_reif(array[int] of var bool: x, var bool: b) = b <-> forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] > x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_strictly_decreasing_int.mzn000066400000000000000000000005511360574160400260670ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in strict decreasing order %-----------------------------------------------------------------------------% predicate fzn_strictly_decreasing_int(array[int] of var int: x) = forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] > x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_strictly_decreasing_int_reif.mzn000066400000000000000000000006011360574160400270700ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in strict decreasing order %-----------------------------------------------------------------------------% predicate fzn_strictly_decreasing_int_reif(array[int] of var int: x, var bool: b) = b <-> forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] > x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_strictly_increasing_bool.mzn000066400000000000000000000005531360574160400262500ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in strict increasing order %-----------------------------------------------------------------------------% predicate fzn_strictly_increasing_bool(array[int] of var bool: x) = forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] < x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_strictly_increasing_bool_reif.mzn000066400000000000000000000006031360574160400272510ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in strict increasing order %-----------------------------------------------------------------------------% predicate fzn_strictly_increasing_bool_reif(array[int] of var bool: x, var bool: b) = b <-> forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] < x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_strictly_increasing_int.mzn000066400000000000000000000005511360574160400261050ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in strict increasing order %-----------------------------------------------------------------------------% predicate fzn_strictly_increasing_int(array[int] of var int: x) = forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] < x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_strictly_increasing_int_reif.mzn000066400000000000000000000006011360574160400271060ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % Requires that the array 'x' is in strict increasing order %-----------------------------------------------------------------------------% predicate fzn_strictly_increasing_int_reif(array[int] of var int: x, var bool: b) = b <-> forall(i in index_set(x) diff { min(index_set(x)) }) (x[i-1] < x[i]); libminizinc-2.4.2/share/minizinc/std/fzn_subcircuit.mzn000066400000000000000000000030431360574160400233270ustar00rootroot00000000000000include "alldifferent.mzn"; predicate fzn_subcircuit(array[int] of var int: x) = let { set of int: S = index_set(x), int: l = min(S), int: u = max(S), int: n = card(S), array[S] of var 1..n: order, array[S] of var bool: ins = array1d(S,[ x[i] != i | i in S]), var l..u+1: firstin = min([ u+1 + bool2int(ins[i])*(i-u-1) | i in S]), var S: lastin, var bool: empty = (firstin > u), } in alldifferent(x) /\ alldifferent(order) /\ % If the subcircuit is empty then each node points at itself. % (empty -> forall(i in S)(not ins[i])) /\ % If the subcircuit is non-empty then order numbers the subcircuit. % ((not empty) -> % The firstin node is numbered 1. order[firstin] = 1 /\ % The lastin node is greater than firstin. lastin > firstin /\ % The lastin node points at firstin. x[lastin] = firstin /\ % And both are in ins[lastin] /\ ins[firstin] /\ % The successor of each node except where it is firstin is % numbered one more than the predecessor. forall(i in S) ( (ins[i] /\ x[i] != firstin) -> order[x[i]] = order[i] + 1 ) /\ % Each node that is not in is numbered after the lastin node. forall(i in S) ( ins[i] \/ order[lastin] < order[i] ) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_subcircuit_reif.mzn000066400000000000000000000003531360574160400243350ustar00rootroot00000000000000include "alldifferent.mzn"; predicate fzn_subcircuit_reif(array[int] of var int: x, var bool: b) = abort("Reified subcircuit/1 is not supported."); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_subgraph_enum.mzn000066400000000000000000000005121360574160400240100ustar00rootroot00000000000000predicate fzn_subgraph(array[int] of $$N: from, array[int] of $$N: to, array[$$N] of var bool: ns, array[int] of var bool: es) = forall(e in index_set(from)) ( (es[e] -> ns[from[e]]) /\ (es[e] -> ns[to[e]]) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_subgraph_enum_reif.mzn000066400000000000000000000006031360574160400250160ustar00rootroot00000000000000predicate fzn_subgraph_reif(array[int] of $$N: from, array[int] of $$N: to, array[$$N] of var bool: ns, array[int] of var bool: es, var bool: b) = b <-> forall(e in index_set(from)) ( (es[e] -> ns[from[e]]) /\ (es[e] -> ns[to[e]]) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_subgraph_int.mzn000066400000000000000000000005171360574160400236430ustar00rootroot00000000000000predicate fzn_subgraph(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of var bool: ns, array[int] of var bool: es) = forall(e in 1..E) ( (es[e] -> ns[from[e]]) /\ (es[e] -> ns[to[e]]) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_subgraph_int_reif.mzn000066400000000000000000000006101360574160400246420ustar00rootroot00000000000000predicate fzn_subgraph_reif(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of var bool: ns, array[int] of var bool: es, var bool: b) = b <-> forall(e in 1..E) ( (es[e] -> ns[from[e]]) /\ (es[e] -> ns[to[e]]) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_sum_pred.mzn000066400000000000000000000004001360574160400227630ustar00rootroot00000000000000predicate fzn_sum_pred(var int: i, array[int] of set of int: sets, array[int] of int: cs, var int: s) = let { array[index_set(sets)] of int: sums = [ sum(i in sets[j])(cs[i]) | j in index_set(sets) ]; } in sums[i] = s; libminizinc-2.4.2/share/minizinc/std/fzn_sum_pred_reif.mzn000066400000000000000000000004411360574160400237750ustar00rootroot00000000000000predicate fzn_sum_pred_reif(var int: i, array[int] of set of int: sets, array[int] of int: cs, var int: s, var bool: b) = let { array[index_set(sets)] of int: sums = [ sum(i in sets[j])(cs[i]) | j in index_set(sets) ]; } in b <-> sums[i] = s; libminizinc-2.4.2/share/minizinc/std/fzn_sum_set.mzn000066400000000000000000000002761360574160400226370ustar00rootroot00000000000000predicate fzn_sum_set(array[int] of int: vs, array[int] of int: ws, var set of int: x, var int: s) = s == sum(j in index_set(vs)) ( bool2int(vs[j] in x) * ws[j] ); libminizinc-2.4.2/share/minizinc/std/fzn_sum_set_reif.mzn000066400000000000000000000003271360574160400236410ustar00rootroot00000000000000predicate fzn_sum_set_reif(array[int] of int: vs, array[int] of int: ws, var set of int: x, var int: s, var bool: b) = b <-> s == sum(j in index_set(vs)) ( bool2int(j in x) * ws[j] ); libminizinc-2.4.2/share/minizinc/std/fzn_symmetric_all_different.mzn000066400000000000000000000002741360574160400260500ustar00rootroot00000000000000include "all_different.mzn"; predicate fzn_symmetric_all_different(array[int] of var int:x) = all_different(x) /\ forall(i, j in index_set(x) where i!=j) (x[i] = j -> x[j] = i); libminizinc-2.4.2/share/minizinc/std/fzn_symmetric_all_different_reif.mzn000066400000000000000000000003401360574160400270470ustar00rootroot00000000000000include "all_different.mzn"; predicate fzn_symmetric_all_different_reif(array[int] of var int:x, var bool: b) = b <-> ( all_different(x) /\ forall(i, j in index_set(x) where i!=j) (x[i] = j -> x[j] = i) ); libminizinc-2.4.2/share/minizinc/std/fzn_table_bool.mzn000066400000000000000000000021141360574160400232530ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % A table constraint: table(x, t) represents the constraint x in t where we % consider each row in t to be a tuple and t as a set of tuples. %-----------------------------------------------------------------------------% predicate fzn_table_bool(array[int] of var bool: x, array[int, int] of bool: t) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), int: lt = min(index_set_1of2(t)), int: ut = max(index_set_1of2(t)), var lt..ut: i, array[l..u, lt..ut] of bool: t_transposed = array2d(l..u, lt..ut, [ t[i,j] | j in l..u, i in lt..ut ]) } in forall(j in l..u) ( % Having the variable index component at the left position % means that the nD-to-1D array translation during Mzn-to-Fzn % will generate at most an offset constraint, instead of a % scaling + offset constraint. % t_transposed[j,i] = x[j] % % t[i,j] = x[j] ); libminizinc-2.4.2/share/minizinc/std/fzn_table_bool_reif.mzn000066400000000000000000000007261360574160400242670ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % A table constraint: table(x, t) represents the constraint x in t where we % consider each row in t to be a tuple and t as a set of tuples. %-----------------------------------------------------------------------------% predicate fzn_table_bool_reif(array[int] of var bool: x, array[int, int] of bool: t, var bool: b) = abort("Reified table/2 for Booleans is not supported."); libminizinc-2.4.2/share/minizinc/std/fzn_table_int.mzn000066400000000000000000000022301360574160400231110ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % A table constraint table(x, t) represents the constraint x in t where we % consider each row in t to be a tuple and t as a set of tuples. %-----------------------------------------------------------------------------% predicate fzn_table_int(array[int] of var int: x, array[int, int] of int: t) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), int: lt = min(index_set_1of2(t)), int: ut = max(index_set_1of2(t)), var lt..ut: i, array[l..u, lt..ut] of int: t_transposed = array2d(l..u, lt..ut, [ t[i,j] | j in l..u, i in lt..ut ]) } in forall(j in l..u) ( % Having the variable index component at the left position % means that the nD-to-1D array translation during Mzn-to-Fzn % will generate at most an offset constraint, instead of a % scaling + offset constraint. % t_transposed[j,i] = x[j] % % t[i,j] = x[j] ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_table_int_reif.mzn000066400000000000000000000071651360574160400241320ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % A table constraint table(x, t) represents the constraint x in t where we % consider each row in t to be a tuple and t as a set of tuples. %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% % Reified version % % We only support special cases of a few variables. % % The approach is to add the Boolean variable to the list of variables and % create an extended table. The extended table covers all combinations of % assignments to the original variables, and every entry in it is padded with a % value that depends on whether that entry occurs in the original table. % % For example, the original table constraint % % x y % --- % 2 3 % 5 8 % 4 1 % % reified with a Boolean b is turned into a table constraint of the form % % x y b % --------- % 2 3 true % 5 8 true % 4 1 true % ... false % ... false % for all other pairs (x,y) % ... false % predicate fzn_table_int_reif(array[int] of var int: x, array[int, int] of int: t, var bool: b) = let { int: n_vars = length(x) } in assert(n_vars in 1..5, "'table' constraints in a reified context " ++ "are only supported for 1..5 variables.", if n_vars = 1 then x[1] in { t[it,1] | it in index_set_1of2(t) } <-> b else let { set of int: ix = index_set(x), set of int: full_size = 1..product(i in ix)( dom_size(x[i]) ), array[full_size, 1..n_vars + 1] of int: t_b = array2d(full_size, 1..n_vars + 1, if n_vars = 2 then [ let { array[ix] of int: tpl = [i1,i2] } in (tpl ++ [bool2int(aux_is_in_table(tpl,t))])[p] | i1 in dom(x[1]), i2 in dom(x[2]), p in 1..n_vars + 1 ] else if n_vars = 3 then [ let { array[ix] of int: tpl = [i1,i2,i3] } in (tpl ++ [bool2int(aux_is_in_table(tpl,t))])[p] | i1 in dom(x[1]), i2 in dom(x[2]), i3 in dom(x[3]), p in 1..n_vars + 1 ] else if n_vars = 4 then [ let { array[ix] of int: tpl = [i1,i2,i3,i4] } in (tpl ++ [bool2int(aux_is_in_table(tpl,t))])[p] | i1 in dom(x[1]), i2 in dom(x[2]), i3 in dom(x[3]), i4 in dom(x[4]), p in 1..n_vars + 1 ] else % if n_vars = 5 then [ let { array[ix] of int: tpl = [i1,i2,i3,i4,i5] } in (tpl ++ [bool2int(aux_is_in_table(tpl,t))])[p] | i1 in dom(x[1]), i2 in dom(x[2]), i3 in dom(x[3]), i4 in dom(x[4]), i5 in dom(x[5]), p in 1..n_vars + 1 ] endif endif endif ) } in fzn_table_int(x ++ [bool2int(b)], t_b) endif ); test aux_is_in_table(array[int] of int: e, array[int, int] of int: t) = exists(i in index_set_1of2(t))( forall(j in index_set(e))( t[i,j] = e[j] ) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_transitive_closure.mzn000066400000000000000000000027001360574160400250760ustar00rootroot00000000000000include "subgraph.mzn"; function array[$$N,$$N] of var bool: fzn_transitive_closure(array[int] of $$N: from, array[int] of $$N: to, var $$N: r, array[$$N] of var bool: ns, array[int] of var bool: es) = let { array[index_set(ns)] of var 0..card(index_set(ns))-1: dist; /* distance from root */ array[index_set(ns)] of var index_set(ns): parent; /* parent */ } in ns[r] /\ % the root must be chosen dist[r] = 0 /\ % root is at distance 0 parent[r] = r /\ % root is its own parent forall(n in index_set(ns)) % nonselected nodes have parent 0 (not ns[n] -> parent[n] = n) /\ forall(n in index_set(ns)) % nonselected nodes have distance 0 (not ns[n] -> dist[n] = 0) /\ forall(n in index_set(ns)) % each in node except root must have a parent (ns[n] -> (n = r \/ parent[n] != n)) /\ forall(n in index_set(ns)) % each in node with a parent must be in and also its parent (parent[n] != n -> (ns[n] /\ ns[parent[n]])) /\ forall(n in index_set(ns)) % each except with a parent is one more than its parent (parent[n] != n -> dist[n] = dist[parent[n]] + 1) /\ forall(n in index_set(ns)) % each node with a parent must have that edge in (parent[n] != n -> exists(e in index_set(from) where to[e] = n)(es[e] /\ from[e] = parent[n])) /\ subgraph(from,to,ns,es); libminizinc-2.4.2/share/minizinc/std/fzn_tree_enum.mzn000066400000000000000000000013141360574160400231350ustar00rootroot00000000000000predicate fzn_tree(array[int] of $$N: from, array[int] of $$N: to, var $$N: r, array[$$N] of var bool: ns, array[int] of var bool: es) = let { int: E = length(es); array[1..2*E] of int: dfrom = from ++ to; array[1..2*E] of int: dto = to ++ from; array[1..2*E] of var bool: des; } in /* ensure that the directed edges selected agree with undirected edges */ forall(e in 1..E)(es[e-1+min(index_set(es))] <-> (des[e] \/ des[e+E])) /\ /* duplicate the edges so that the we can use directed graph reachability */ fzn_dtree(dfrom,dto,r,ns,des); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_tree_enum_reif.mzn000066400000000000000000000005241360574160400241440ustar00rootroot00000000000000predicate fzn_tree_reif(array[int] of $$N: from, array[int] of $$N: to, var $$N: r, array[$$N] of var bool: ns, array[int] of var bool: es, var bool: b) = abort("Reified tree constraint is not supported"); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_tree_int.mzn000066400000000000000000000013061360574160400227640ustar00rootroot00000000000000include "subgraph.mzn"; predicate fzn_tree(int: N, int: E, array[int] of int: from, array[int] of int: to, var int: r, array[int] of var bool: ns, array[int] of var bool: es) = let { array[1..2*E] of int: dfrom = from ++ to; array[1..2*E] of int: dto = to ++ from; array[1..2*E] of var bool: des; } in /* ensure that the directed edges selected agree with undirected edges */ forall(e in 1..E)(es[e] <-> (des[e] \/ des[e+E])) /\ /* duplicate the edges so that the we can use directed graph reachability */ fzn_dtree(N,2*E,dfrom,dto,r,ns,des); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_tree_int_reif.mzn000066400000000000000000000005141360574160400237710ustar00rootroot00000000000000predicate fzn_tree_reif(int: N, int: E, array[int] of int: from, array[int] of int: to, var int: r, array[int] of var bool: ns, array[int] of var bool: es, var bool: b) = abort("Reified tree constraint is not supported"); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_value_precede_chain_int.mzn000066400000000000000000000011761360574160400257770ustar00rootroot00000000000000include "seq_precede_chain.mzn"; predicate fzn_value_precede_chain_int(array[int] of int: T, array[int] of var int: X) = if min(index_set(T)) = 1 /\ forall (i in index_set(T))(T[i] = i) /\ max(T) = ub_array(X) then seq_precede_chain(X) else let { int: l = lb_array(X); int: u = ub_array(X); array[1.. u -l +1] of int : p = [sum([i | i in index_set(T) where T[i] = j]) | j in l..u]; array [int] of var 0..length(T): Y = array1d(index_set(X),[p[X[i]-l+1] | i in index_set(X)]); } in seq_precede_chain(Y) endif; libminizinc-2.4.2/share/minizinc/std/fzn_value_precede_chain_int_reif.mzn000066400000000000000000000002561360574160400270020ustar00rootroot00000000000000predicate fzn_value_precede_chain_int_reif(array[int] of int: T, array[int] of var int: X, var bool: b) = abort("Reified value_precede_chain constraint is not supported"); libminizinc-2.4.2/share/minizinc/std/fzn_value_precede_chain_set.mzn000066400000000000000000000003541360574160400257750ustar00rootroot00000000000000include "value_precede.mzn"; predicate fzn_value_precede_chain_set(array[int] of int: c, array[int] of var set of int: x) = forall (i in min(index_set(c)) + 1 .. max(index_set(c))) ( value_precede(c[i - 1], c[i], x) ); libminizinc-2.4.2/share/minizinc/std/fzn_value_precede_chain_set_reif.mzn000066400000000000000000000002521360574160400267770ustar00rootroot00000000000000predicate fzn_value_precede_chain_set_reif(array[int] of int: c, array[int] of var set of int: x, var bool: b) = abort("Reified value_precede_chain is not supported"); libminizinc-2.4.2/share/minizinc/std/fzn_value_precede_int.mzn000066400000000000000000000010101360574160400246200ustar00rootroot00000000000000predicate fzn_value_precede_int(int: s, int: t, array[int] of var int: x) = let { int: imin = min(index_set(x)), int: imax = max(index_set(x)), array[imin..imax+1] of var bool: b } in ( forall (i in imin..imax) ( let { var bool: xis = (x[i] == s) } in (xis -> (b[i+1] == true)) /\ ((not xis) -> (b[i] == b[i+1])) /\ ((not b[i]) -> (x[i] != t)) ) /\ b[imin] == false ); libminizinc-2.4.2/share/minizinc/std/fzn_value_precede_int_reif.mzn000066400000000000000000000003111360574160400256300ustar00rootroot00000000000000predicate fzn_value_precede_int_reif(int: s, int: t, array[int] of var int: x, var bool: b) = abort("Reified value_precede/3 for integers is not supported."); libminizinc-2.4.2/share/minizinc/std/fzn_value_precede_set.mzn000066400000000000000000000010731360574160400246320ustar00rootroot00000000000000predicate fzn_value_precede_set(int: s, int: t, array[int] of var set of int: x) = let { int: imin = min(index_set(x)), int: imax = max(index_set(x)), array[imin..imax + 1] of var bool: b } in ( forall (i in imin..imax) ( let { var bool: xis = (s in x[i] /\ not (t in x[i])) } in (xis -> (b[i + 1] == true)) /\ ((not xis) -> (b[i] == b[i + 1])) /\ ((not b[i]) -> (s in x[i] \/ not (t in x[i]))) ) /\ b[imin] == false ); libminizinc-2.4.2/share/minizinc/std/fzn_value_precede_set_reif.mzn000066400000000000000000000003021360574160400256310ustar00rootroot00000000000000predicate fzn_value_precede_set_reif(int: s, int: t, array[int] of var set of int: x, var bool: b) = abort("Reified value_precede/3 for sets is not supported."); libminizinc-2.4.2/share/minizinc/std/fzn_write.mzn000066400000000000000000000004311360574160400223030ustar00rootroot00000000000000predicate fzn_write(array[int] of var int: I, var int: i, var int: v, array[int] of var int: O) = forall(j in index_set(I)) (O[j] = if j = i then v else I[j] endif); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_write_reif.mzn000066400000000000000000000004671360574160400233210ustar00rootroot00000000000000predicate fzn_write_reif(array[int] of var int: I, var int: i, var int: v, array[int] of var int: O, var bool: b) = b <-> forall(j in index_set(I)) (O[j] = if j = i then v else I[j] endif); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_writes.mzn000066400000000000000000000006331360574160400224720ustar00rootroot00000000000000predicate fzn_writes(array[int] of var int: I, array[int] of var int: P, array[int] of var int: V, array[int] of var int: O) = forall(j in index_set(P))(O[P[j]] = V[j]) /\ forall(i in index_set(I)) (if forall(j in index_set(P))(P[j] != i) then O[i] = I[i] else true endif); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_writes_reif.mzn000066400000000000000000000007511360574160400235000ustar00rootroot00000000000000predicate fzn_writes_reif(array[int] of var int: I, array[int] of var int: P, array[int] of var int: V, array[int] of var int: O, var bool: b) = b <-> ( forall(j in index_set(P))(O[P[j]] = V[j]) /\ forall(i in index_set(I)) (if forall(j in index_set(P))(P[j] != i) then O[i] = I[i] else true endif) ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_writes_seq.mzn000066400000000000000000000011031360574160400233330ustar00rootroot00000000000000include "arg_max.mzn"; predicate fzn_writes_seq(array[int] of var int: I, array[int] of var int: P, array[int] of var int: V, array[int] of var int: O) = forall (i in index_set(I)) ( let { array[1..length(V)+1] of var int: Vi = array1d(1..length(V)+1, reverse(V) ++ [I[i]]); array[1..length(V)+1] of var bool: Pi = array1d(1..length(V)+1, reverse([P[j] == i | j in index_set(V)]) ++ [true]); } in O[i] = Vi[arg_max(Pi)] ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_writes_seq_reif.mzn000066400000000000000000000011761360574160400243520ustar00rootroot00000000000000include "arg_max.mzn"; predicate fzn_writes_seq_reif(array[int] of var int: I, array[int] of var int: P, array[int] of var int: V, array[int] of var int: O, var bool: b) = b <-> forall (i in index_set(I)) ( let { array[1..length(V)+1] of var int: Vi = array1d(1..length(V)+1, reverse(V) ++ [I[i]]); array[1..length(V)+1] of var bool: Pi = array1d(1..length(V)+1, reverse([P[j] == i | j in index_set(V)]) ++ [true]); } in O[i] = Vi[arg_max(Pi)] ); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_wst.mzn000066400000000000000000000007011360574160400217660ustar00rootroot00000000000000include "tree.mzn"; predicate fzn_wst(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of int: w, array[int] of var bool: es, var int: K) = let { var 1..N: r; /* root of tree */ array[1..N] of bool: ns = [true | n in 1..N]; } in tree(N,E,from,to,r,ns,es) /\ K = sum(e in 1..E)(es[e]*w[e]); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/fzn_wst_reif.mzn000066400000000000000000000005031360574160400227730ustar00rootroot00000000000000predicate fzn_wst_reif(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of int: w, array[int] of var bool: es, var int: K, var bool: b) = abort("Reified wst constraint is not supported"); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/geost.mzn000066400000000000000000000213431360574160400214220ustar00rootroot00000000000000include "fzn_geost.mzn"; include "fzn_geost_reif.mzn"; include "fzn_geost_bb.mzn"; include "fzn_geost_bb_reif.mzn"; include "fzn_geost_smallest_bb.mzn"; include "fzn_geost_smallest_bb_reif.mzn"; include "fzn_geost_nonoverlap_k.mzn"; include "fzn_geost_nonoverlap_k_reif.mzn"; /** @group globals.packing A global non-overlap constraint for \a k dimensional objects. It enforces that no two objects overlap. @param k: the number of dimensions @param rect_size: the size of each box in \a k dimensios @param rect_offset: the offset of each box from the base position in \a k dimensions @param shape: the set of rectangles defining the \p i-th shape. @param x: the base position of each object. \a x[\p i,\p j] is the position of object \p i in. dimension \p j. @param kind: the shape used by each object. */ predicate geost( int : k , array[int,int] of int : rect_size , array[int,int] of int : rect_offset , array[int ] of set of int : shape , array[int,int] of var int : x , array[int ] of var int : kind ) = assert( % Some sanity checks index_set_1of2( rect_size ) = index_set_1of2(rect_offset) /\ index_set_2of2( rect_size ) = 1..k /\ index_set_2of2( rect_offset ) = 1..k /\ index_set( shape ) = 1..length(shape) /\ index_set_1of2( x ) = index_set(kind) /\ index_set_2of2( x ) = 1..k /\ forall(i in index_set(shape))( shape[i] subset index_set_1of2(rect_size) ), % Error message "geost: index sets of arguments are incorrect", assert( % More sanity checks forall(i in index_set(shape))(card(shape[i]) > 0), % Error message "geost: sets in shape must be non-empty", fzn_geost(k, rect_size, rect_offset, shape, x, kind) )); % End assert statements /** @group globals.packing A global non-overlap constraint for \a k dimensional objects. It enforces that no two objects overlap, and that all objects fit within a global \a k dimensional bounding box. @param k: the number of dimensions @param rect_size: the size of each box in \a k dimensios @param rect_offset: the offset of each box from the base position in \a k dimensions @param shape: the set of rectangles defining the \p i-th shape. @param x: the base position of each object. \a x[\p i,\p j] is the position of object \p i in dimension \p j. @param kind: the shape used by each object. @param l: is an array of lower bounds, \a l[\p i] is the minimum bounding box for all objects in dimension \p i. @param u: is an array of upper bounds, \a u[\p i] is the maximum bounding box for all objects in dimension \p i. */ predicate geost_bb( int : k , array[int,int] of int : rect_size , array[int,int] of int : rect_offset , array[int ] of set of int : shape , array[int,int] of var int : x , array[int ] of var int : kind , array[int ] of var int : l , array[int ] of var int : u ) = assert( % Some sanity checks index_set_1of2( rect_size ) = index_set_1of2(rect_offset) /\ index_set_2of2( rect_size ) = 1..k /\ index_set_2of2( rect_offset ) = 1..k /\ index_set( shape ) = 1..length(shape) /\ index_set_1of2( x ) = index_set(kind) /\ index_set_2of2( x ) = 1..k /\ forall(i in index_set(shape))( shape[i] subset index_set_1of2(rect_size) ), % Error message "geost_bb: index sets of arguments are incorrect", assert( % More sanity checks forall(i in index_set(shape))(card(shape[i]) > 0), % Error message "geost_bb: sets in shape must be non-empty", assert( % Sanity check index_set(l) = 1..k /\ index_set(u) = 1..k, % Error message "geost_bb: index set of bounds arrays is not 1.." ++ show(k), % Posting the geost constraint fzn_geost_bb(k, rect_size, rect_offset, shape, x, kind, l, u) ))); /** @group globals.packing A global non-overlap constraint for \a k dimensional objects. It enforces that no two objects overlap, and that all objects fit within a global \a k dimensional bounding box. In addition, it enforces that the bounding box is the smallest one containing all objects, i.e., each of the \a 2k boundaries is touched by at least by one object. @param k: the number of dimensions @param rect_size: the size of each box in \a k dimensios @param rect_offset: the offset of each box from the base position in \a k dimensions @param shape: the set of rectangles defining the \p i-th shape. @param x: the base position of each object. \a x[\p i,\p j] is the position of object \p i in dimension \p j. @param kind: the shape used by each object. @param l: is an array of lower bounds, \a l[\p i] is the minimum bounding box for all objects in dimension \p i. @param u: is an array of upper bounds, \a u[\p i] is the maximum bounding box for all objects in dimension \p i. */ predicate geost_smallest_bb( int : k , array[int,int] of int : rect_size , array[int,int] of int : rect_offset , array[int ] of set of int : shape , array[int,int] of var int : x , array[int ] of var int : kind , array[int ] of var int : l , array[int ] of var int : u ) = assert( % Some sanity checks index_set_1of2( rect_size ) = index_set_1of2(rect_offset) /\ index_set_2of2( rect_size ) = 1..k /\ index_set_2of2( rect_offset ) = 1..k /\ index_set( shape ) = 1..length(shape) /\ index_set_1of2( x ) = index_set(kind) /\ index_set_2of2( x ) = 1..k /\ forall(i in index_set(shape))( shape[i] subset index_set_1of2(rect_size) ), % Error message "geost_bb: index sets of arguments are incorrect", assert( % More sanity checks forall(i in index_set(shape))(card(shape[i]) > 0), % Error message "geost_bb: sets in shape must be non-empty", % A few useful definitions let { set of int: DIMS = 1..k; set of int: SHAPES = 1..length(shape); set of int: OBJECTS = index_set(kind); } in % Two useful definitions let { set of int: DIMS = 1..k; set of int: OBJECTS = index_set(kind); } in ( assert( % Sanity check index_set(l) = 1..k /\ index_set(u) = 1..k, % Error message "geost_bb: index set of bounds arrays is not 1.." ++ show(k), % Posting the geost constraint fzn_geost_smallest_bb(k, rect_size, rect_offset, shape, x, kind, l, u) )))); /** @group globals.packing A global non-overlap constraint for \a 2 dimensional objects. It enforces that no two objects overlap and zero-length objects do not appear in the middle of other objects. @param x1: first coordinate of each object @param w2: width in first dimension for each object @param x2: second coordinate of each object @param w2: width in second dimension for each object */ predicate geost_nonoverlap_k( array[int] of var int : x1, array[int] of int : w1, array[int] of var int : x2, array[int] of int : w2 ) = assert( % Some sanity checks index_set( x1 ) = index_set( w1 ) /\ index_set( x1 ) = index_set( x2 ) /\ index_set( x1 ) = index_set( w2 ), % Error message "geost_nonoverlap_k: index sets of arguments do not match", % Non-overlap constraint fzn_geost_nonoverlap_k(x1,w1,x2,w2) ); test geost_nonoverlap_k( array[int] of int: x1, array[int] of int: w1, array[int] of int: x2, array[int] of int: w2 ) = assert( % Some sanity checks index_set( x1 ) = index_set( w1 ) /\ index_set( x1 ) = index_set( x2 ) /\ index_set( x1 ) = index_set( w2 ), % Error message "geost_nonoverlap_k: index sets of arguments do not match", % Non-overlap test exists(j in index_set(x1))( x1[j] + w1[j] <= x2[j] \/ x2[j] + w2[j] <= x1[j] ) ); libminizinc-2.4.2/share/minizinc/std/global_cardinality.mzn000066400000000000000000000010321360574160400241150ustar00rootroot00000000000000include "fzn_global_cardinality.mzn"; include "fzn_global_cardinality_reif.mzn"; /** @group globals.counting Requires that the number of occurrences of \a cover[\p i] in \a x is \a counts[\p i]. */ predicate global_cardinality(array[int] of var int: x, array[int] of int: cover, array[int] of var int: counts) = assert(index_set(cover) = index_set(counts), "global_cardinality: cover and counts must have identical index sets", fzn_global_cardinality(x, cover, counts) ); libminizinc-2.4.2/share/minizinc/std/global_cardinality_closed.mzn000066400000000000000000000012371360574160400254550ustar00rootroot00000000000000include "fzn_global_cardinality_closed.mzn"; include "fzn_global_cardinality_closed_reif.mzn"; /** @group globals.counting Requires that the number of occurences of \p i in \a x is \a counts[\p i]. The elements of \a x must take their values from \a cover. */ predicate global_cardinality_closed(array[int] of var int: x, array[int] of int: cover, array[int] of var int: counts) = assert(index_set(cover) = index_set(counts), "global_cardinality_closed: " ++ "cover and counts must have identical index sets", fzn_global_cardinality_closed(x, cover, counts) ); libminizinc-2.4.2/share/minizinc/std/global_cardinality_closed_fn.mzn000066400000000000000000000007701360574160400261410ustar00rootroot00000000000000include "global_cardinality_closed.mzn"; /** @group globals.counting Returns an array with number of occurences of \p i in \a x. The elements of \a x must take their values from \a cover. */ function array[int] of var int: global_cardinality_closed(array[int] of var int: x, array[int] of int: cover) :: promise_total = let { array[index_set(cover)] of var 0..length(x): counts; constraint global_cardinality_closed(x,cover,counts); } in counts; libminizinc-2.4.2/share/minizinc/std/global_cardinality_fn.mzn000066400000000000000000000006351360574160400246100ustar00rootroot00000000000000include "global_cardinality.mzn"; /** @group globals.counting Returns the number of occurrences of \a cover[\p i] in \a x. */ function array[int] of var int: global_cardinality(array[int] of var int: x, array[int] of int: cover) :: promise_total = let { array[index_set(cover)] of var 0..length(x): counts; constraint global_cardinality(x,cover,counts) } in counts; libminizinc-2.4.2/share/minizinc/std/global_cardinality_low_up.mzn000066400000000000000000000011071360574160400255050ustar00rootroot00000000000000include "fzn_global_cardinality_low_up.mzn"; include "fzn_global_cardinality_low_up_reif.mzn"; /** @group globals.counting Requires that for all \p i, the value \a cover[\p i] appears at least \a lbound[\p i] and at most \a ubound[\p i] times in the array \a x. */ predicate global_cardinality_low_up(array[int] of var int: x, array[int] of int: cover, array[int] of int: lbound, array[int] of int: ubound) = fzn_global_cardinality_low_up(x,cover,lbound,ubound); libminizinc-2.4.2/share/minizinc/std/global_cardinality_low_up_closed.mzn000066400000000000000000000012661360574160400270440ustar00rootroot00000000000000include "fzn_global_cardinality_low_up_closed.mzn"; include "fzn_global_cardinality_low_up_closed_reif.mzn"; /** @group globals.counting Requires that for all \p i, the value \a cover[\p i] appears at least \a lbound[\p i] and at most \a ubound[\p i] times in the array \a x. The elements of \a x must take their values from \a cover. */ predicate global_cardinality_low_up_closed(array[int] of var int: x, array[int] of int: cover, array[int] of int: lbound, array[int] of int: ubound) = fzn_global_cardinality_low_up_closed(x, cover, lbound, ubound); libminizinc-2.4.2/share/minizinc/std/globals.mzn000066400000000000000000000077341360574160400217340ustar00rootroot00000000000000/*** @groupdef globals Global constraints These constraints represent high-level modelling abstractions, for which many solvers implement special, efficient inference algorithms. */ /*** @groupdef globals.alldifferent All-Different and related constraints @groupdef globals.lexicographic Lexicographic constraints @groupdef globals.sort Sorting constraints @groupdef globals.channeling Channeling constraints @groupdef globals.counting Counting constraints These constraints count and restrict how many times certain values occur in an array of variables. MiniZinc will automatically generate the basic counting constraints below from expressions such as \[count(i in x)(i=c) <= d\], so you can write models in this much more readable style instead of using these predicates. However, if your model contains multiple counting constraints over the same array, constraints like \[distribute\] or \[global_cardinality\] below may be useful. @groupdef globals.packing Packing constraints @groupdef globals.scheduling Scheduling constraints @groupdef globals.graph Graph constraints @groupdef globals.extensional Extensional constraints (table, regular etc.) @groupdef globals.learning Machine learning constraints @groupdef globals.deprecated Deprecated constraints */ include "all_different.mzn"; include "alldifferent_except_0.mzn"; include "all_disjoint.mzn"; include "all_equal.mzn"; include "alternative.mzn"; include "among.mzn"; include "among_fn.mzn"; include "arg_sort.mzn"; include "arg_min.mzn"; include "arg_max.mzn"; include "at_least.mzn"; include "at_most.mzn"; include "at_most1.mzn"; include "bin_packing.mzn"; include "bin_packing_capa.mzn"; include "bin_packing_load.mzn"; include "bin_packing_load_fn.mzn"; include "bounded_path.mzn"; include "circuit.mzn"; include "connected.mzn"; include "cost_mdd.mzn"; include "cost_regular.mzn"; include "count.mzn"; include "count_fn.mzn"; include "cumulative.mzn"; include "cumulative_opt.mzn"; include "dag.mzn"; include "decreasing.mzn"; include "diffn.mzn"; include "diffn_nonstrict.mzn"; include "diffn_k.mzn"; include "diffn_nonstrict_k.mzn"; include "disjoint.mzn"; include "disjunctive.mzn"; include "disjunctive_strict.mzn"; include "disjunctive_opt.mzn"; include "disjunctive_strict_opt.mzn"; include "distribute.mzn"; include "distribute_fn.mzn"; include "element.mzn"; include "exactly.mzn"; include "geost.mzn"; include "global_cardinality.mzn"; include "global_cardinality_fn.mzn"; include "global_cardinality_closed.mzn"; include "global_cardinality_closed_fn.mzn"; include "global_cardinality_low_up.mzn"; include "global_cardinality_low_up_closed.mzn"; include "increasing.mzn"; include "int_set_channel.mzn"; include "inverse.mzn"; include "inverse_fn.mzn"; include "inverse_set.mzn"; include "knapsack.mzn"; include "lex_greater.mzn"; include "lex_greatereq.mzn"; include "lex_lesseq.mzn"; include "lex_less.mzn"; include "lex2.mzn"; include "link_set_to_booleans.mzn"; include "maximum.mzn"; include "mdd.mzn"; include "mdd_nondet.mzn"; include "member.mzn"; include "minimum.mzn"; include "network_flow.mzn"; include "neural_net.mzn"; include "nvalue.mzn"; include "nvalue_fn.mzn"; include "partition_set.mzn"; include "piecewise_linear.mzn"; include "range.mzn"; include "range_fn.mzn"; include "reachable.mzn"; include "regular.mzn"; include "regular_nfa.mzn"; include "regular_set.mzn"; include "regular_regexp.mzn"; include "roots.mzn"; include "roots_fn.mzn"; include "seq_precede_chain.mzn"; include "sliding_sum.mzn"; include "sort.mzn"; include "sort_fn.mzn"; include "span.mzn"; include "steiner.mzn"; include "strictly_decreasing.mzn"; include "strictly_increasing.mzn"; include "strict_lex2.mzn"; include "subcircuit.mzn"; include "subgraph.mzn"; include "sum_pred.mzn"; include "sum_set.mzn"; include "symmetric_all_different.mzn"; include "table.mzn"; include "tree.mzn"; include "value_precede.mzn"; include "value_precede_chain.mzn"; include "weighted_spanning_tree.mzn"; libminizinc-2.4.2/share/minizinc/std/increasing.mzn000066400000000000000000000015211360574160400224170ustar00rootroot00000000000000include "increasing_bool.mzn"; include "increasing_float.mzn"; include "increasing_int.mzn"; include "increasing_set.mzn"; /** @group globals.sort Requires that the array \a x is in increasing order (duplicates are allowed). */ predicate increasing(array[int] of var bool: x) = increasing_bool(x); /** @group globals.sort Requires that the array \a x is in increasing order (duplicates are allowed). */ predicate increasing(array[int] of var float: x) = increasing_float(x); /** @group globals.sort Requires that the array \a x is in increasing order (duplicates are allowed). */ predicate increasing(array[int] of var int: x) = increasing_int(x); /** @group globals.sort Requires that the array \a x is in increasing order (duplicates are allowed). */ predicate increasing(array[int] of var set of int: x) = increasing_set(x); libminizinc-2.4.2/share/minizinc/std/increasing_bool.mzn000066400000000000000000000006171360574160400234370ustar00rootroot00000000000000include "fzn_increasing_bool.mzn"; include "fzn_increasing_bool_reif.mzn"; %-----------------------------------------------------------------------------% % Requires that the array 'x' is in increasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate increasing_bool(array[int] of var bool: x) = fzn_increasing_bool(x); libminizinc-2.4.2/share/minizinc/std/increasing_float.mzn000066400000000000000000000006251360574160400236100ustar00rootroot00000000000000include "fzn_increasing_float.mzn"; include "fzn_increasing_float_reif.mzn"; %-----------------------------------------------------------------------------% % Requires that the array 'x' is in increasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate increasing_float(array[int] of var float: x) = fzn_increasing_float(x); libminizinc-2.4.2/share/minizinc/std/increasing_int.mzn000066400000000000000000000006121360574160400232710ustar00rootroot00000000000000include "fzn_increasing_int.mzn"; include "fzn_increasing_int_reif.mzn"; %-----------------------------------------------------------------------------% % Requires that the array 'x' is in increasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate increasing_int(array[int] of var int: x) = fzn_increasing_int(x); libminizinc-2.4.2/share/minizinc/std/increasing_set.mzn000066400000000000000000000006211360574160400232720ustar00rootroot00000000000000include "fzn_increasing_set.mzn"; include "fzn_increasing_set_reif.mzn"; %-----------------------------------------------------------------------------% % Requires that the array 'x' is in increasing order (duplicates are allowed). %-----------------------------------------------------------------------------% predicate increasing_set(array[int] of var set of int: x) = fzn_increasing_set(x); libminizinc-2.4.2/share/minizinc/std/int_set_channel.mzn000066400000000000000000000007611360574160400234370ustar00rootroot00000000000000include "fzn_int_set_channel.mzn"; include "fzn_int_set_channel_reif.mzn"; /** @group globals.channeling Requires that array of int variables \a x and array of set variables \a y are related such that (\a x[\p i] = \p j) \( \leftrightarrow \) (\p i in \a y[\p j]). */ predicate int_set_channel(array[int] of var int: x, array[int] of var set of int: y) = fzn_int_set_channel(x,y); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/inverse.mzn000066400000000000000000000012311360574160400217460ustar00rootroot00000000000000include "fzn_inverse.mzn"; include "fzn_inverse_reif.mzn"; include "analyse_all_different.mzn"; /** @group globals.channeling Constrains two arrays of int variables, \a f and \a invf, to represent inverse functions. All the values in each array must be within the index set of the other array. */ predicate inverse(array[int] of var int: f, array[int] of var int: invf) = analyse_all_different(f) /\ analyse_all_different(invf) /\ fzn_inverse(f, invf); predicate inverse_reif(array[int] of var int: f, array[int] of var int: invf, var bool: b) = fzn_inverse_reif(f, invf, b); libminizinc-2.4.2/share/minizinc/std/inverse_fn.mzn000066400000000000000000000007621360574160400224410ustar00rootroot00000000000000include "inverse.mzn"; /** @group globals.channeling Given a function \a f represented as an array, return the inverse function. */ function array[$$E] of var $$F: inverse(array[$$F] of var $$E: f) = let { array[lb_array(f)..ub_array(f)] of var index_set(f): invf; constraint inverse(f,invf); } in invf; /** @group globals.channeling Given a function \a f represented as an array, return the inverse function. */ function array[$$E] of $$F: inverse(array[$$F] of $$E: f); libminizinc-2.4.2/share/minizinc/std/inverse_set.mzn000066400000000000000000000007041360574160400226250ustar00rootroot00000000000000include "fzn_inverse_set.mzn"; include "fzn_inverse_set_reif.mzn"; /** @group globals.channeling Constrains two arrays of set of int variables, \a f and \a invf, so that a \p j in f[\p i] iff \p i in invf[\p j]. All the values in each array's sets must be within the index set of the other array. */ predicate inverse_set(array[int] of var set of int: f, array[int] of var set of int: invf) = fzn_inverse_set(f,invf); libminizinc-2.4.2/share/minizinc/std/knapsack.mzn000066400000000000000000000017441360574160400220770ustar00rootroot00000000000000include "fzn_knapsack.mzn"; include "fzn_knapsack_reif.mzn"; /** @group globals.packing Requires that items are packed in a knapsack with certain weight and profit restrictions. Assumptions: - Weights \a w and profits \a p must be non-negative - \a w, \a p and \a x must have the same index sets @param w: weight of each type of item @param p: profit of each type of item @param x: number of items of each type that are packed @param W: sum of sizes of all items in the knapsack @param P: sum of profits of all items in the knapsack */ predicate knapsack(array[int] of int: w, array[int] of int:p, array[int] of var int:x, var int: W, var int: P) = assert(index_set(w) = index_set(p) /\ index_set(w) = index_set(x), "index set of weights must be equal to index set of profits and index set of items", assert(lb_array(w) >= 0, "weights must be non-negative", assert(lb_array(p) >= 0, "profits must be non-negative", fzn_knapsack(w, p, x, W, P) ))); libminizinc-2.4.2/share/minizinc/std/lex2.mzn000066400000000000000000000004541360574160400211530ustar00rootroot00000000000000include "fzn_lex2.mzn"; include "fzn_lex2_reif.mzn"; /** @group globals.lexicographic Require adjacent rows and adjacent columns in the array \a x to be lexicographically ordered. Adjacent rows and adjacent columns may be equal. */ predicate lex2(array[int, int] of var int: x) = fzn_lex2(x); libminizinc-2.4.2/share/minizinc/std/lex_greater.mzn000066400000000000000000000024231360574160400226000ustar00rootroot00000000000000include "lex_less.mzn"; /** @group globals.lexicographic Requires that the array \a x is strictly lexicographically greater than array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_greater(array[int] of var bool: x, array[int] of var bool: y) = lex_less(y, x); /** @group globals.lexicographic Requires that the array \a x is strictly lexicographically greater than array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_greater(array[int] of var int: x, array[int] of var int: y) = lex_less(y, x); /** @group globals.lexicographic Requires that the array \a x is strictly lexicographically greater than array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_greater(array[int] of var float: x, array[int] of var float: y) = lex_less(y, x); /** @group globals.lexicographic Requires that the array \a x is strictly lexicographically greater than array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_greater(array[int] of var set of int: x, array[int] of var set of int: y) = lex_less(y, x); libminizinc-2.4.2/share/minizinc/std/lex_greatereq.mzn000066400000000000000000000024351360574160400231310ustar00rootroot00000000000000include "lex_lesseq.mzn"; /** @group globals.lexicographic Requires that the array \a x is lexicographically greater than or equal to array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_greatereq(array[int] of var bool: x, array[int] of var bool: y) = lex_lesseq(y, x); /** @group globals.lexicographic Requires that the array \a x is lexicographically greater than or equal to array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_greatereq(array[int] of var int: x, array[int] of var int: y) = lex_lesseq(y, x); /** @group globals.lexicographic Requires that the array \a x is lexicographically greater than or equal to array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_greatereq(array[int] of var float: x, array[int] of var float: y) = lex_lesseq(y, x); /** @group globals.lexicographic Requires that the array \a x is lexicographically greater than or equal to array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_greatereq(array[int] of var set of int: x, array[int] of var set of int: y) = lex_lesseq(y, x); libminizinc-2.4.2/share/minizinc/std/lex_less.mzn000066400000000000000000000046261360574160400221240ustar00rootroot00000000000000include "lex_less_bool.mzn"; include "lex_less_float.mzn"; include "lex_less_int.mzn"; include "lex_less_set.mzn"; /** @group globals.lexicographic Requires that the array \a x is strictly lexicographically less than array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_less(array[int] of var bool: x, array[int] of var bool: y) = if length(x)=1 /\ length(y)=1 then x[min(index_set(x))] < y[min(index_set(y))] elseif length(x)=0 then length(y)>0 elseif length(y)=0 then false else lex_less_bool(x, y) endif; /** @group globals.lexicographic Requires that the array \a x is strictly lexicographically less than array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_less(array[int] of var int: x, array[int] of var int: y) = if length(x)=1 /\ length(y)=1 then x[min(index_set(x))] < y[min(index_set(y))] elseif length(x)=0 then length(y)>0 elseif length(y)=0 then false else lex_less_int(x, y) endif; /** @group globals.lexicographic Requires that the array \a x is strictly lexicographically less than array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_less(array[int] of var float: x, array[int] of var float: y) = if length(x)=1 /\ length(y)=1 then x[min(index_set(x))] < y[min(index_set(y))] elseif length(x)=0 then length(y)>0 elseif length(y)=0 then false else lex_less_float(x, y) endif; /** @group globals.lexicographic Requires that the array \a x is strictly lexicographically less than array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_less(array[int] of var set of int: x, array[int] of var set of int: y) = if length(x)=1 /\ length(y)=1 then x[min(index_set(x))] < y[min(index_set(y))] elseif length(x)=0 then length(y)>0 elseif length(y)=0 then false else lex_less_set(x, y) endif; % Alternative names for the above. % predicate lex_lt(array[int] of var bool: x, array[int] of var bool: y) = lex_less(x, y); predicate lex_lt(array[int] of var int: x, array[int] of var int: y) = lex_less(x, y); predicate lex_lt(array[int] of var float: x, array[int] of var float: y) = lex_less(x, y); predicate lex_lt(array[int] of var set of int: x, array[int] of var set of int: y) = lex_less(x, y); libminizinc-2.4.2/share/minizinc/std/lex_less_bool.mzn000066400000000000000000000013431360574160400231300ustar00rootroot00000000000000include "lex_less.mzn"; include "fzn_lex_less_bool.mzn"; include "fzn_lex_less_bool_reif.mzn"; %-----------------------------------------------------------------------------% % Requires that the array 'x' is strictly lexicographically less than array 'y'. % Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate lex_less_bool(array[int] of var bool: x, array[int] of var bool: y) = fzn_lex_less_bool(x, y); predicate lex_lt_bool(array[int] of var bool: x, array[int] of var bool: y) = lex_less(x, y); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/lex_less_float.mzn000066400000000000000000000013561360574160400233060ustar00rootroot00000000000000include "lex_less.mzn"; include "fzn_lex_less_float.mzn"; include "fzn_lex_less_float_reif.mzn"; %-----------------------------------------------------------------------------% % Requires that the array 'x' is strictly lexicographically less than array 'y'. % Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate lex_less_float(array[int] of var float: x, array[int] of var float: y) = fzn_lex_less_float(x, y); predicate lex_lt_float(array[int] of var float: x, array[int] of var float: y) = lex_less(x, y); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/lex_less_int.mzn000066400000000000000000000013361360574160400227710ustar00rootroot00000000000000include "lex_less.mzn"; include "fzn_lex_less_int.mzn"; include "fzn_lex_less_int_reif.mzn"; %-----------------------------------------------------------------------------% % Requires that the array 'x' is strictly lexicographically less than array 'y'. % Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate lex_less_int(array[int] of var int: x, array[int] of var int: y) = fzn_lex_less_int(x, y); predicate lex_lt_int(array[int] of var int: x, array[int] of var int: y) = lex_less(x, y); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/lex_less_set.mzn000066400000000000000000000013641360574160400227730ustar00rootroot00000000000000include "lex_less.mzn"; include "fzn_lex_less_set.mzn"; include "fzn_lex_less_set_reif.mzn"; %-----------------------------------------------------------------------------% % Requires that the array 'x' is strictly lexicographically less than array 'y'. % Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate lex_less_set(array[int] of var set of int: x, array[int] of var set of int: y) = fzn_lex_less_set(x, y); predicate lex_lt_set(array[int] of var set of int: x, array[int] of var set of int: y) = lex_less(x, y); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/lex_lesseq.mzn000066400000000000000000000046671360574160400224570ustar00rootroot00000000000000include "lex_lesseq_bool.mzn"; include "lex_lesseq_float.mzn"; include "lex_lesseq_int.mzn"; include "lex_lesseq_set.mzn"; /** @group globals.lexicographic Requires that the array \a x is lexicographically less than or equal to array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_lesseq(array[int] of var bool: x, array[int] of var bool: y) = if length(x)=1 /\ length(y)=1 then x[min(index_set(x))] <= y[min(index_set(y))] elseif length(x)=0 then true elseif length(y)=0 then false else lex_lesseq_bool(x, y) endif; /** @group globals.lexicographic Requires that the array \a x is lexicographically less than or equal to array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_lesseq(array[int] of var float: x, array[int] of var float: y) = if length(x)=1 /\ length(y)=1 then x[min(index_set(x))] <= y[min(index_set(y))] elseif length(x)=0 then true elseif length(y)=0 then false else lex_lesseq_float(x, y) endif; /** @group globals.lexicographic Requires that the array \a x is lexicographically less than or equal to array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_lesseq(array[int] of var int: x, array[int] of var int: y) = if length(x)=1 /\ length(y)=1 then x[min(index_set(x))] <= y[min(index_set(y))] elseif length(x)=0 then true elseif length(y)=0 then false else lex_lesseq_int(x, y) endif; /** @group globals.lexicographic Requires that the array \a x is lexicographically less than or equal to array \a y. Compares them from first to last element, regardless of indices. */ predicate lex_lesseq(array[int] of var set of int: x, array[int] of var set of int: y) = if length(x)=1 /\ length(y)=1 then x[min(index_set(x))] <= y[min(index_set(y))] elseif length(x)=0 then true elseif length(y)=0 then false else lex_lesseq_set(x, y) endif; % Alternative names for the above. % predicate lex_leq(array[int] of var bool: x, array[int] of var bool: y) = lex_lesseq(x, y); predicate lex_leq(array[int] of var int: x, array[int] of var int: y) = lex_lesseq(x, y); predicate lex_leq(array[int] of var float: x, array[int] of var float: y) = lex_lesseq(x, y); predicate lex_leq(array[int] of var set of int: x, array[int] of var set of int: y) = lex_lesseq(x, y); libminizinc-2.4.2/share/minizinc/std/lex_lesseq_bool.mzn000066400000000000000000000013421360574160400234550ustar00rootroot00000000000000include "fzn_lex_lesseq_bool.mzn"; include "fzn_lex_lesseq_bool_reif.mzn"; %-----------------------------------------------------------------------------% % Requires that the array 'x' is lexicographically less than or equal to % array 'y'. Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate lex_lesseq_bool(array[int] of var bool: x, array[int] of var bool: y) = fzn_lex_lesseq_bool(x, y); predicate lex_leq_bool(array[int] of var bool: x, array[int] of var bool: y) = lex_lesseq_bool(x, y); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/lex_lesseq_float.mzn000066400000000000000000000013561360574160400236340ustar00rootroot00000000000000include "fzn_lex_lesseq_float.mzn"; include "fzn_lex_lesseq_float_reif.mzn"; %-----------------------------------------------------------------------------% % Requires that the array 'x' is lexicographically less than or equal to % array 'y'. Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate lex_lesseq_float(array[int] of var float: x, array[int] of var float: y) = fzn_lex_lesseq_float(x, y); predicate lex_leq_float(array[int] of var float: x, array[int] of var float: y) = lex_lesseq_float(x, y); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/lex_lesseq_int.mzn000066400000000000000000000013261360574160400233160ustar00rootroot00000000000000include "fzn_lex_lesseq_int.mzn"; include "fzn_lex_lesseq_int_reif.mzn"; %-----------------------------------------------------------------------------% % Requires that the array 'x' is lexicographically less than or equal to % array 'y'. Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate lex_lesseq_int(array[int] of var int: x, array[int] of var int: y) = fzn_lex_lesseq_int(x, y); predicate lex_leq_int(array[int] of var int: x, array[int] of var int: y) = lex_lesseq_int(x, y); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/lex_lesseq_set.mzn000066400000000000000000000013621360574160400233170ustar00rootroot00000000000000include "fzn_lex_lesseq_set.mzn"; include "fzn_lex_lesseq_set_reif.mzn"; %-----------------------------------------------------------------------------% % Requires that the array 'x' is lexicographically less than or equal to % array 'y'. Compares them from first to last element, regardless of indices %-----------------------------------------------------------------------------% predicate lex_lesseq_set(array[int] of var set of int: x, array[int] of var set of int: y) = fzn_lex_lesseq_set(x, y); predicate lex_leq_set(array[int] of var set of int: x, array[int] of var set of int: y) = lex_lesseq_set(x, y); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/link_set_to_booleans.mzn000066400000000000000000000011121360574160400244650ustar00rootroot00000000000000include "fzn_link_set_to_booleans.mzn"; include "fzn_link_set_to_booleans_reif.mzn"; /** @group globals.channeling Constrain the array of Booleans \a b to be a representation of the set \a s: \p i in \a s \( \leftrightarrow \) \a b[\p i]. The index set of \a b must be a superset of the possible values of \a s. */ predicate link_set_to_booleans(var set of int: s, array[int] of var bool: b) = assert(ub(s) subset index_set(b), "link_set_to_booleans: the index set of b must be a superset of the possible values of s", fzn_link_set_to_booleans(s,b) ); libminizinc-2.4.2/share/minizinc/std/maximum.mzn000066400000000000000000000006131360574160400217530ustar00rootroot00000000000000/** @group globals Constrains \a m to be the maximum of the values in \a x. Assumptions: |\a x| > 0. */ predicate maximum(var int: m, array[int] of var int: x) = array_int_maximum(m, x); /** @group globals Constrains \a m to be the maximum of the values in \a x. Assumptions: |\a x| > 0. */ predicate maximum(var float: m, array[int] of var float: x) = array_float_maximum(m, x); libminizinc-2.4.2/share/minizinc/std/mdd.mzn000066400000000000000000000060501360574160400210430ustar00rootroot00000000000000include "fzn_mdd.mzn"; include "fzn_mdd_reif.mzn"; /** @group globals.extensional Requires that \a x defines a path from root to true node T through the (deterministic) MDD defined by @param N: the number of nodes, the root node is node 1 @param level: the level of each node, the root is level 1, T is level \a length(x)+1 @param E: the number of edges @param from: the leaving node (1..\a N)for each edge @param label: the set of values of the \a x variable for each edge @param to: the entering node for each edge, where 0 = T node The MDD must be deterministic, i.e., there cannot be two edges with the same label leaving the same node. */ predicate mdd(array[int] of var int: x, % variables constrained by MDD int: N, % number of nodes root is node 1 array[int] of int: level, % level of each node root is level 1, T is level length(x)+1 int: E, % number of edges array[int] of int: from, % edge leaving node 1..N array[int] of set of int: label, % possible values of variable array[int] of int: to % edge entering node 0..N where 0 = T node ) = let { set of int: NODE = 1..N; set of int: EDGE = 1..E; int: L = length(x); array[0..N] of int: levele = array1d(0..N,[L+1]++level); } in assert(index_set(level) = NODE, "mdd: third argument must be of length N = \(N)") /\ assert(index_set(from) = EDGE, "mdd: 5th argument must be of length E = \(E)") /\ assert(index_set(to) = EDGE, "mdd: 7th argument must be of length E = \(E)") /\ forall(e in EDGE)(assert(from[e] in NODE, "mdd: from[\(e)] must be in \(NODE)")) /\ forall(e in EDGE)(assert(to[e] in 0..N, "mdd: to[\(e)] must be in 0..\(N)")) /\ forall(e in EDGE)(assert(level[from[e]]+1 = levele[to[e]], "mdd level of from[\(e)] = \(level[from[e]])" ++ "must be 1 less than level of to[\(e)] = \(levele[to[e]])")) /\ forall(e1,e2 in EDGE where e1 < e2 /\ from[e1] = from[e2]) (assert(label[e1] intersect label[e2] = {}, "mdd: Two edges \(e1) and \(e2) leaving node \(from[e1]) with overlapping labels")) /\ fzn_mdd(x, N, level, E, from, label, to); % Example consider an MDD over 3 variables % 5 nodes and 12 edges % level 1 root = 1 % level 2 2 3 % level 3 4 5 % level 4 T % with edges (from,label,to) given by % (1,1,2), (1,2,3), (1,3,2) % (2,2,4), (2,3,5) % (3,3,4), (3,2,5) % (4,1,0), (4,5,0) % (5,2,0), (5,4,0), (5,6,0) % this is defined by the call % mdd([x1,x2,x3],5,[1,2,2,3,3],12,[1,1,1,2,2,3,3,4,4,5,5,5],[1,3,2,2,3,3,2,1,5,2,4,6],[2,2,3,4,5,4,5,0,0,0,0,0]) libminizinc-2.4.2/share/minizinc/std/mdd_nondet.mzn000066400000000000000000000056151360574160400224200ustar00rootroot00000000000000include "fzn_mdd_nondet.mzn"; include "fzn_mdd_nondet_reif.mzn"; /** @group globals.extensional Requires that \a x defines a path from root to true node T through the (nondeterministic) MDD defined by @param N: the number of nodes, the root node is node 1 @param level: the level of each node, the root is level 1, T is level \a length(x)+1 @param E: the number of edges @param from: the leaving node (1..\a N)for each edge @param label: the set of values of the \a x variable for each edge @param to: the entering node for each edge, where 0 = T node The MDD can be nondeterministic, i.e., there can be two edges with the same label leaving the same node. */ predicate mdd_nondet(array[int] of var int: x, % variables constrained by MDD int: N, % number of nodes root is node 1 array[int] of int: level, % level of each node root is level 1, T is level length(x)+1 int: E, % number of edges array[int] of int: from, % edge leaving node 1..N array[int] of set of int: label, % possible values of variable array[int] of int: to % edge entering node 0..N where 0 = T node ) = let { set of int: NODE = 1..N; set of int: EDGE = 1..E; int: L = length(x); array[0..N] of int: levele = array1d(0..N,[L+1]++level); } in assert(index_set(level) = NODE, "mdd: third argument must be of length N = \(N)") /\ assert(index_set(from) = EDGE, "mdd: 5th argument must be of length E = \(E)") /\ assert(index_set(to) = EDGE, "mdd: 7th argument must be of length E = \(E)") /\ forall(e in EDGE)(assert(from[e] in NODE, "mdd: from[\(e)] must be in \(NODE)")) /\ forall(e in EDGE)(assert(to[e] in 0..N, "mdd: to[\(e)] must be in 0..\(N)")) /\ forall(e in EDGE)(assert(level[from[e]]+1 = levele[to[e]], "mdd level of from[\(e)] = \(level[from[e]])" ++ "must be 1 less than level of to[\(e)] = \(levele[to[e]])")) /\ fzn_mdd_nondet(x, N, level, E, from, label, to); % Example consider an MDD over 3 variables % 5 nodes and 12 edges % level 1 root = 1 % level 2 2 3 % level 3 4 5 % level 4 T % with edges (from,label,to) given by % (1,1,2), (1,2,3), (1,3,2) % (2,2,4), (2,3,5) % (3,3,4), (3,2,5) % (4,1,0), (4,5,0) % (5,2,0), (5,4,0), (5,6,0) % this is defined by the call % mdd([x1,x2,x3],5,[1,2,2,3,3],12,[1,1,1,2,2,3,3,4,4,5,5,5],[1,3,2,2,3,3,2,1,5,2,4,6],[2,2,3,4,5,4,5,0,0,0,0,0]) libminizinc-2.4.2/share/minizinc/std/member.mzn000066400000000000000000000015741360574160400215540ustar00rootroot00000000000000include "member_bool.mzn"; include "member_float.mzn"; include "member_int.mzn"; include "member_set.mzn"; include "set_member.mzn"; /** @group globals Requires that \a y occurs in the array \a x. */ predicate member(array[int] of var bool: x, var bool: y) = member_bool(x, y); /** @group globals Requires that \a y occurs in the array \a x. */ predicate member(array[int] of var float: x, var float: y) = member_float(x, y); /** @group globals Requires that \a y occurs in the array \a x. */ predicate member(array[int] of var int: x, var int: y) = member_int(x, y); /** @group globals Requires that \a y occurs in the array \a x. */ predicate member(array[int] of var set of int: x, var set of int: y) = member_set(x, y); /** @group globals Requires that \a y occurs in the set \a x. */ predicate member(var set of int: x, var int: y) = set_member(x, y); libminizinc-2.4.2/share/minizinc/std/member_bool.mzn000066400000000000000000000005641360574160400225650ustar00rootroot00000000000000include "fzn_member_bool.mzn"; include "fzn_member_bool_reif.mzn"; %-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array or set 'x'. %-----------------------------------------------------------------------------% predicate member_bool(array[int] of var bool: x, var bool: y) = fzn_member_bool(x, y); libminizinc-2.4.2/share/minizinc/std/member_float.mzn000066400000000000000000000005721360574160400227360ustar00rootroot00000000000000include "fzn_member_float.mzn"; include "fzn_member_float_reif.mzn"; %-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array or set 'x'. %-----------------------------------------------------------------------------% predicate member_float(array[int] of var float: x, var float: y) = fzn_member_float(x, y); libminizinc-2.4.2/share/minizinc/std/member_int.mzn000066400000000000000000000005561360574160400224250ustar00rootroot00000000000000include "fzn_member_int.mzn"; include "fzn_member_int_reif.mzn"; %-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array or set 'x'. %-----------------------------------------------------------------------------% predicate member_int(array[int] of var int: x, var int: y) = fzn_member_int(x, y); libminizinc-2.4.2/share/minizinc/std/member_set.mzn000066400000000000000000000005741360574160400224260ustar00rootroot00000000000000include "fzn_member_set.mzn"; include "fzn_member_set_reif.mzn"; %-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array or set 'x'. %-----------------------------------------------------------------------------% predicate member_set(array[int] of var set of int: x, var set of int: y) = fzn_member_set(x, y); libminizinc-2.4.2/share/minizinc/std/minimum.mzn000066400000000000000000000006131360574160400217510ustar00rootroot00000000000000/** @group globals Constrains \a m to be the minimum of the values in \a x. Assumptions: |\a x| > 0. */ predicate minimum(var float: m, array[int] of var float: x) = array_float_minimum(m, x); /** @group globals Constrains \a m to be the minimum of the values in \a x. Assumptions: |\a x| > 0. */ predicate minimum(var int: m, array[int] of var int: x) = array_int_minimum(m, x); libminizinc-2.4.2/share/minizinc/std/network_flow.mzn000066400000000000000000000036101360574160400230160ustar00rootroot00000000000000include "fzn_network_flow.mzn"; include "fzn_network_flow_reif.mzn"; include "fzn_network_flow_cost.mzn"; include "fzn_network_flow_cost_reif.mzn"; /** @group globals Defines a network flow constraint. @param arc: a directed arc of the flow network. Arc \p i connects node \a arc[\p i,1] to node \a arc[\p i,2]. @param balance: the difference between input and output flow for each node. @param flow: the flow going through each arc. */ predicate network_flow(array[int,1..2] of int: arc, array[int] of int: balance, array[int] of var int: flow) = let { set of int: ARCS = index_set_1of2(arc); set of int: NODES = index_set(balance); } in assert ( ARCS == index_set(flow) /\ lb_array(arc) >= min(NODES) /\ ub_array(arc) <= max(NODES), "network_flow: wrong sizes of input array parameters", fzn_network_flow(arc, balance, flow) ); /** @group globals Defines a network flow constraint with cost. @param arc: a directed arc of the flow network. Arc \p i connects node \a arc[\p i,1] to node \a arc[\p i,2]. @param balance: the difference between input and output flow for each node. @param weight: the unit cost of the flow through the arc. @param flow: the flow going through each arc. @param cost: the overall cost of the flow. */ predicate network_flow_cost(array[int,1..2] of int: arc, array[int] of int: balance, array[int] of int: weight, array[int] of var int: flow, var int: cost) = let { set of int: ARCS = index_set_1of2(arc); set of int: NODES = index_set(balance); } in assert ( ARCS == index_set(flow) /\ ARCS == index_set(weight) /\ lb_array(arc) >= min(NODES) /\ ub_array(arc) <= max(NODES), "network_flow: wrong sizes of input array parameters", fzn_network_flow_cost(arc, balance, weight, flow, cost) ); libminizinc-2.4.2/share/minizinc/std/neural_net.mzn000066400000000000000000000067431360574160400224440ustar00rootroot00000000000000include "fzn_neural_net.mzn"; include "fzn_neural_net_reif.mzn"; enum NEURON_TYPE = { NT_RELU, NT_STEP, NT_LINEAR, NT_SOFTPLUS }; /** @group globals.learning constrain the output layer of a neural net to take the value defined by the input layer. the arguments are \a inputs: an array of float variables \a input_ids: array[int] of node \a outputs: an array of float variables \a output_ids: array[int] of node \a bias: array[node] of float \a edge_weight: array[edge] of float (dummy one at end!) \a edge_parent: array[edge] of neuron (start neuron for edge) \a first_edge: array[node] of 1..m+1 \a neuron_type: { NT_RELU, NT_STEP, NT_LINEAR, NT_SOFTPLUS } */ predicate neural_net(array[int] of var float: inputs, array[int] of int: input_ids, array[int] of var float: outputs, array[int] of int: output_ids, array[int] of float: bias, array[int] of float: edge_weight, array[int] of int: edge_parent, array[int] of int: first_edge, NEURON_TYPE: neuron_type) = assert(index_set(inputs) == index_set(input_ids), "neural_net: number of input vars not equal to number of input_ids") /\ assert(index_set(outputs) == index_set(output_ids), "neural_net: number of output vars not equal to number of output_ids") /\ let { set of int: node = index_set(bias) } in let { set of int: edge = index_set(edge_weight) } in assert(index_set(edge_parent) == edge, "neural_net: index sets of edge_weight and edge_parent do not agree") /\ assert(index_set(first_edge) == node, "neural_new: index sets of bias and first_edge do not agree") /\ forall(i in index_set(input_ids)) (assert(input_ids[i] in node, "neural_net: input_ids\(i) = \(input_ids[i]) not a correct node number")) /\ forall(i in index_set(output_ids)) (assert(output_ids[i] in node, "neural_net: output_ids\(i) = \(output_ids[i]) not a correct node number")) /\ forall(i in index_set(first_edge)) (assert(first_edge[i] in edge, "neural_net: first_edge\(i) = \(first_edge[i]) not a correct edge number")) /\ forall(i in index_set(edge_parent)) (assert(edge_parent[i] in edge, "neural_net: edge_parent\(i) = \(edge_parent[i]) not a correct node number")) /\ assert(mincreasing(first_edge), "neural_net: first_edge array is not in increasing order") /\ fzn_neural_net(inputs,input_ids,outputs,output_ids,bias, edge_weight,edge_parent,first_edge,neuron_type); test mincreasing(array[int] of int: x) = forall(i in index_set(x) diff { max(index_set(x)) }) (x[i] <= x[i+1]); predicate neural_net(array[int] of var float: inputs, array[int] of int: input_ids, array[int] of var float: outputs, array[int] of int: output_ids, array[int] of float: bias, array[int] of float: edge_weight, array[int] of int: edge_parent, array[int] of int: first_edge) = neural_net(inputs,input_ids,outputs,output_ids,bias, edge_weight,edge_parent,first_edge,NT_RELU); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/nosets.mzn000066400000000000000000000347521360574160400216240ustar00rootroot00000000000000%%% Inclusion of this file eliminates set variables by converting them into arrays of var bool. % AUTHORS % Guido Tack % Gleb Belov % predicate mzn_reverse_map_var(var set of int: x) = let { array[int] of var bool: b = set2bools(x) } in true; function var set of int: reverse_map_ab2si(array[int] of var bool: b); function set of int: reverse_map_ab2si(array[int] of bool: b) ::promise_total = { i | i in index_set(b) where b[i] }; array[int] of var bool: set2bools(var set of int: x) ::promise_total = if is_fixed(x) then set2bools(fix(x)) else let { array[int] of var bool: b = array1d( min(ub(x))..max(ub(x)), [ set2bools_bit( x, i ) | i in min(ub(x))..max(ub(x)) ] ); constraint (x = reverse_map_ab2si(b)) :: is_reverse_map; } in b endif; array[int] of var bool: set2bools(var set of int: x, set of int: ubx) ::promise_total = if is_fixed(x) then set2bools(fix(x), ubx) else let { array[int] of var bool: b0 = set2bools( x ); %% Call in any case ?? TODO array[int] of var bool: b = array1d( min(ubx)..max(ubx), [ if i in ubx then set2bools_bit( x, i ) else false endif | i in min(ubx)..max(ubx) ] ); } in b endif; array[int] of bool: set2bools(set of int: x) ::promise_total = array1d(min(x)..max(x),[i in x | i in min(x)..max(x)]); array[int] of bool: set2bools(set of int: x, set of int: ubx) ::promise_total = array1d(min(ubx)..max(ubx),[i in x | i in min(ubx)..max(ubx)]); function var bool: set2bools_bit( var set of int: x, int: i ) ::promise_total = if i in ub(x) then let { var bool: bi; } in bi else false endif; predicate set_eq(var set of int: x, var set of int: y) ::promise_total = if not has_ub_set(x) /\ not has_ub_set(y) then assert(false, "set_eq: cannot determine bounds of set variables") elseif not has_ub_set(x) then set_eq(y,x) else let { constraint y subset x, %% Constrain domains first constraint x subset y, } in let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); } in forall (i in index_set(bx) union index_set(by)) ( if not (i in index_set(bx)) then not by[i] %% Should be impossible elseif not (i in index_set(by)) then not bx[i] else bx[i]=by[i] endif ) endif; predicate set_eq_reif(var set of int: x, var set of int: y, var bool: b) ::promise_total = if is_fixed(b) then if true==fix(b) then x==y else x!=y endif else let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); } in b <-> forall (i in index_set(bx) union index_set(by)) ( if not (i in index_set(bx)) then not by[i] elseif not (i in index_set(by)) then not bx[i] else bx[i]=by[i] endif ) endif; predicate set_eq_imp(var set of int: x, var set of int: y, var bool: b) = if is_fixed(b) then if fix(b) then (x = y) else true endif else let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); } in b -> forall (i in index_set(bx) union index_set(by)) ( if not (i in index_set(bx)) then not by[i] elseif not (i in index_set(by)) then not bx[i] else bx[i]=by[i] endif ) endif; predicate set_ne(var set of int: x, var set of int: y) ::promise_total = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); } in exists (i in index_set(bx) union index_set(by)) ( if not (i in index_set(bx)) then by[i] elseif not (i in index_set(by)) then bx[i] else bx[i]!=by[i] endif ); predicate set_ne_reif(var set of int: x, var set of int: y, var bool: b) ::promise_total = set_eq_reif( x, y, not b ); predicate set_ne_imp(var set of int: x, var set of int: y, var bool: b) = if is_fixed(b) then if fix(b) then (x != y) else true endif else let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); } in b -> exists (i in index_set(bx) union index_set(by)) ( if not (i in index_set(bx)) then by[i] elseif not (i in index_set(by)) then bx[i] else (bx[i] != by[i]) endif ) endif; % Set comparisons are often used just to avoid symmetries. predicate set_le(var set of int: x, var set of int: y) = let { set of int: U = ub(x) union ub(y); int: l = min(U); int: u = max(U); array[l..u] of var bool: xb = [i in x | i in l..u]; var l-1..u: xmax = max(x union {l-1}); array[l..u] of var bool: yb = [i in y | i in l..u]; var l-1..u: ymax = max(y union {l-1}); array[l..u] of var bool: b; constraint forall(i in l..u-1) ( b[i] = let {var 1..4: cmp = 2*xb[i] + yb[i] + 1} in [b[i+1], xmax < i, ymax > i, b[i+1]][cmp] ); constraint b[u] = (xb[u] -> yb[u]); } in b[l]; predicate set_le_reif(var set of int: x, var set of int: y, var bool: r) = let { set of int: U = ub(x) union ub(y); int: l = min(U); int: u = max(U); array[l..u] of var bool: xb = [i in x | i in l..u]; var l-1..u: xmax = max(x union {l-1}); array[l..u] of var bool: yb = [i in y | i in l..u]; var l-1..u: ymax = max(y union {l-1}); array[l..u] of var bool: b; constraint forall(i in l..u-1) ( b[i] = let {var 1..4: cmp = 2*xb[i] + yb[i] + 1} in [b[i+1], xmax < i, ymax > i, b[i+1]][cmp] ); constraint b[u] = (xb[u] -> yb[u]); } in r <-> b[l]; predicate set_le_imp(var set of int: x, var set of int: y, var bool: r) = let { set of int: U = ub(x) union ub(y); int: l = min(U); int: u = max(U); array[l..u] of var bool: xb = [i in x | i in l..u]; var l-1..u: xmax = max(x union {l-1}); array[l..u] of var bool: yb = [i in y | i in l..u]; var l-1..u: ymax = max(y union {l-1}); array[l..u] of var bool: b; constraint forall(i in l..u-1) ( b[i] = let {var 1..4: cmp = 2*xb[i] + yb[i] + 1} in [b[i+1], xmax < i, ymax > i, b[i+1]][cmp] ); constraint b[u] = (xb[u] -> yb[u]); } in r -> b[l]; predicate set_lt(var set of int: x, var set of int: y) ::promise_total = let { set of int: U = ub(x) union ub(y); int: l = min(U); int: u = max(U); array[l..u] of var bool: xb = [i in x | i in l..u]; var l-1..u: xmax = max(x union {l-1}); array[l..u] of var bool: yb = [i in y | i in l..u]; var l-1..u: ymax = max(y union {l-1}); array[l..u] of var bool: b; constraint forall(i in l..u-1) ( b[i] = let {var 1..4: cmp = 2*xb[i] + yb[i] + 1} in [b[i+1], xmax < i, ymax > i, b[i+1]][cmp] ); constraint b[u] = (not xb[u] /\ yb[u]); } in b[l]; predicate set_lt_reif(var set of int: x, var set of int: y, var bool: r) ::promise_total = let { set of int: U = ub(x) union ub(y); int: l = min(U); int: u = max(U); array[l..u] of var bool: xb = [i in x | i in l..u]; var l-1..u: xmax = max(x union {l-1}); array[l..u] of var bool: yb = [i in y | i in l..u]; var l-1..u: ymax = max(y union {l-1}); array[l..u] of var bool: b; constraint forall(i in l..u-1) ( b[i] = let {var 1..4: cmp = 2*xb[i] + yb[i] + 1} in [b[i+1], xmax < i, ymax > i, b[i+1]][cmp] ); constraint b[u] = (not xb[u] /\ yb[u]); } in r <-> b[l]; predicate set_lt_imp(var set of int: x, var set of int: y, var bool: r) ::promise_total = let { set of int: U = ub(x) union ub(y); int: l = min(U); int: u = max(U); array[l..u] of var bool: xb = [i in x | i in l..u]; var l-1..u: xmax = max(x union {l-1}); array[l..u] of var bool: yb = [i in y | i in l..u]; var l-1..u: ymax = max(y union {l-1}); array[l..u] of var bool: b; constraint forall(i in l..u-1) ( b[i] = let {var 1..4: cmp = 2*xb[i] + yb[i] + 1} in [b[i+1], xmax < i, ymax > i, b[i+1]][cmp] ); constraint b[u] = (not xb[u] /\ yb[u]); } in r -> b[l]; predicate set_subset(var set of int: x, var set of int: y) ::promise_total = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); } in forall (i in index_set(bx)) ( if not (i in index_set(by)) then not bx[i] else bx[i] -> by[i] endif ); predicate set_subset_reif(var set of int: x, var set of int: y, var bool: b) ::promise_total = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); } in b <-> forall (i in index_set(bx)) ( if not (i in index_set(by)) then not bx[i] else bx[i] -> by[i] endif ); predicate set_subset_imp(var set of int: x, var set of int: y, var bool: b) = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); } in b -> forall (i in index_set(bx)) ( if not (i in index_set(by)) then not bx[i] else bx[i] -> by[i] endif ); %%% Map the subset operation to superset predicate set_superset(var set of int: x, var set of int: y) ::promise_total = set_subset( y, x ); predicate set_superset_reif(var set of int: x, var set of int: y, var bool: b) ::promise_total = set_subset_reif( y, x, b ); predicate set_superset_imp(var set of int: x, var set of int: y, var bool: b) = set_subset_imp(y,x,b); function var set of int: set_intersect(var set of int: x, var set of int: y) ::promise_total = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); var set of (index_set(bx) intersect index_set(by)): z; array[int] of var bool: bz = set2bools(z); constraint forall (i in index_set(bz)) ( bz[i] = (bx[i] /\ by[i]) ); } in z; function var set of int: set_union(var set of int: x, var set of int: y) ::promise_total = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); var set of (index_set(bx) union index_set(by)): z; array[int] of var bool: bz = set2bools(z); constraint forall (i in index_set(bx) union index_set(by)) ( if (i in index_set(bx)) then if (i in index_set(by)) then bz[i] = (bx[i] \/ by[i]) else bz[i] = bx[i] endif else bz[i] = by[i] endif ); } in z; function var set of int: set_diff(var set of int: x, var set of int: y) ::promise_total = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); var set of ub(x) diff lb(y): z; array[int] of var bool: bz = set2bools(z); constraint forall (i in ub(z)) ( bz[i] = (bx[i] /\ (not by[i])) ); } in z; function var set of int: set_symdiff(var set of int: x, var set of int: y) ::promise_total = let { array[int] of var bool: bx = set2bools(x); array[int] of var bool: by = set2bools(y); var set of (ub(x) diff lb(y)) union (ub(y) diff lb(x)): z; array[int] of var bool: bz = set2bools(z); constraint forall (i in ub(z)) ( bz[i] = (bx[i] xor by[i]) ); } in z; predicate set_card(var set of int: x, var int: c) = let { array[int] of var bool: bx = set2bools(x); } in bool_lin_eq([1 | i in index_set(bx)],[bx[i] | i in index_set(bx)],c); predicate set_in(int: x, var set of int: y) ::promise_total = let { array[int] of var bool: by = set2bools(y); } in by[x]; predicate set_in(var int: x, var set of int: y) ::promise_total = let { array[int] of var bool: by = set2bools(y); } in by[x]; predicate set_in_reif(int: x, var set of int: y, var bool: b) ::promise_total = if x in ub(y) then b <-> set2bools(y)[x] else not b endif; predicate set_in_reif(var int: x, var set of int: y, var bool: b) ::promise_total = b <-> set2bools(y)[x]; predicate set_in_imp(var int: x, var set of int: y, var bool: b) = b -> set2bools(y)[x]; function array[int] of var bool: setarray2bools(array[int] of var set of int: x) = if length(x)=0 then [] else set2bools(x[1])++setarray2bools([x[i]|i in 2..length(x)]) endif; %% Par version no sense predicate array_var_set_element(var int: x, array[int] of var set of int: y, var set of int: z) ::promise_total = let { constraint x in { i | i in index_set( y ) where lb(y[i]) subset ub(z) /\ lb(z) subset ub(y[i]) }; set of int: sUB = array_union( [ ub(y[i]) | i in dom(x) ] ); set of int: sLB = array_intersect( [ lb(y[i]) | i in dom(x) ] ); constraint z subset sUB, constraint sLB subset z, } in forall (k in ub(z)) ( set2bools(z)[k] == if k in sUB then if k in sLB then true else array1d( lb(x)..ub(x), [ if k in ub(y[i]) then set2bools(y[i])[k] else false endif | i in lb(x)..ub(x) ] )[x] endif else false endif ) /\ forall (k in sUB diff ub(z))( if k in sLB then false %% fail the constraint else not array1d( lb(x)..ub(x), [ if k in ub(y[i]) then set2bools(y[i])[k] else false endif | i in lb(x)..ub(x) ] )[x] endif ); predicate array_set_element(var int: x, array[int] of set of int: y, var set of int: z) ::promise_total = let { constraint x in { i | i in index_set( y ) where y[i] subset ub(z) /\ lb(z) subset y[i] }; set of int: sUB = array_union( [ y[i] | i in dom(x) ] ); set of int: sLB = array_intersect( [ y[i] | i in dom(x) ] ); constraint z subset sUB, constraint sLB subset z, } in forall (k in ub(z)) ( set2bools(z)[k] == if k in sUB then if k in sLB then true else array1d( lb(x)..ub(x), [ if k in ub(y[i]) then set2bools(y[i])[k] else false endif | i in lb(x)..ub(x) ] )[x] endif else false endif ) /\ forall (k in sUB diff ub(z))( if k in sLB then false %% fail the constraint else not array1d( lb(x)..ub(x), [ if k in ub(y[i]) then set2bools(y[i])[k] else false endif | i in lb(x)..ub(x) ] )[x] endif ); annotation set_search(array[$X] of var set of int: x, ann: a1, ann: a2, ann: a3) = let { array[int] of var set of int: xx = array1d(x) } in seq_search( [ bool_search(set2bools(xx[i]),a1,a2,a3) | i in index_set(xx) ] ); annotation warm_start( array[int] of var set of int: x, array[int] of set of int: v ) = warm_start_array( [ let { array[int] of var bool: xb = set2bools(x[i]), set of int: is_var = ub(x[i]) diff lb(x[i]), int: iV = i - min(index_set(x)) + if 0 b) /\ forall (i in index_set(bs)) (bs[i] \/ b); /** @group flatzinc.two Constrains \a m to be the maximum value in array \a x. */ predicate array_int_maximum(var int: m, array[int] of var int: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), int: ly = lb_array(x), int: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == max(x[i],y[i-1]) ); /** @group flatzinc.two Constrains \a m to be the maximum value in array \a x. */ predicate array_float_maximum(var float: m, array[int] of var float: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), float: ly = lb_array(x), float: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == max(x[i],y[i-1]) ); /** @group flatzinc.two Constrains \a m to be the minimum value in array \a x. */ predicate array_int_minimum(var int: m, array[int] of var int: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), int: ly = lb_array(x), int: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == min(x[i],y[i-1]) ); /** @group flatzinc.two Constrains \a m to be the minimum value in array \a x. */ predicate array_float_minimum(var float: m, array[int] of var float: x) = let { int: l = min(index_set(x)), int: u = max(index_set(x)), float: ly = lb_array(x), float: uy = ub_array(x), array[l..u] of var ly..uy: y } in y[l] = x[l] /\ m = y[u] /\ forall (i in l+1 .. u) ( y[i] == min(x[i],y[i-1]) ); libminizinc-2.4.2/share/minizinc/std/redefinitions-2.1.1.mzn000066400000000000000000000052311360574160400235760ustar00rootroot00000000000000% This file contains redefinitions of standard builtins for version 2.1.1 % that can be overridden by solvers. /*** @groupdef flatzinc.twooneone FlatZinc builtins added in MiniZinc 2.1.1. These functions and predicates define built-in operations of the MiniZinc language that have been added in MiniZinc 2.1.1. Solvers that support these natively need to include a file called redefinitions-2.1.1.mzn in their solver library that redefines these predicates as builtins. */ /** @group flatzinc.twooneone Returns variable constrained to be equal to the minimum of the set \a s. An alternative implementation can be found in the comments of the source code. */ function var $$E: min(var set of $$E: s) = let { var min(ub(s)) .. max(ub(s)): m = min([ e + (max(ub(s))+1-e)*(1 - (e in s)) | e in ub(s) ]) } in m; %% The following can be used as an alternative if the solver supports %% a FlatZinc builtin set_min: % predicate set_min(var set of int: s, var int: m); % % function var $$E: min(var set of $$E: s) = % if mzn_in_root_context(s) then min_t(s) else % let { constraint card(s) > 0 } in min_mt(s) endif; % % function var $$E: min_t(var set of $$E: s) ::promise_total = % let { % var min(ub(s))..max(ub(s)): ms ::is_defined_var; % constraint card(s) > 0; % constraint set_min(s,ms) ::defines_var(ms); % } in ms; % % function var $$E: min_mt(var set of $$E: s) ::promise_total = % let { % var set of ub(s) union {1}: x; % var bool: b = card(s) > 0; % constraint b -> x=s; % constraint b \/ 1 in x; % } in min_t(x); /** @group flatzinc.twooneone Returns variable constrained to be equal to the maximum of the set \a s. An alternative implementation can be found in the comments of the source code. */ function var $$E: max(var set of $$E: s) = let { var min(ub(s)) .. max(ub(s)): m = max([ e + (min(ub(s))-1-e)*(1 - (e in s)) | e in ub(s) ]) } in m; %% The following can be used as an alternative if the solver supports %% a FlatZinc builtin set_max: % predicate set_max(var set of int: s, var int: m); % % function var $$E: max(var set of $$E: s) = % if mzn_in_root_context(s) then max_t(s) else % let { constraint card(s) > 0 } in max_mt(s) endif; % % function var $$E: max_t(var set of $$E: s) ::promise_total = % let { % var min(ub(s))..max(ub(s)): ms ::is_defined_var; % constraint card(s) > 0; % constraint set_max(s,ms) ::defines_var(ms); % } in ms; % % function var $$E: max_mt(var set of $$E: s) ::promise_total = % let { % var set of ub(s) union {1}: x; % var bool: b = card(s) > 0; % constraint b -> x=s; % constraint b \/ 1 in x; % } in max_t(x); libminizinc-2.4.2/share/minizinc/std/redefinitions-2.1.mzn000066400000000000000000000014101360574160400234320ustar00rootroot00000000000000/*** @groupdef flatzinc.twoone FlatZinc builtins added in MiniZinc 2.1.0. These functions and predicates define built-in operations of the MiniZinc language that have been added in MiniZinc 2.1.0. Solvers that support these natively need to include a file called redefinitions-2.1.0.mzn in their solver library that redefines these predicates as builtins. */ /** @group flatzinc.twoone Constrains \a a ≤ \a x ≤ \a b */ predicate float_in(var float: x, float: a, float: b) = x >= a /\ x <= b; /** @group flatzinc.twoone Constrains \a x to take one of the values in \a as */ predicate float_dom(var float: x, array[int] of float: as) = let { array[int] of var bool: b = [float_in(x,as[2*i-1],as[2*i]) | i in 1..length(as) div 2] } in exists(b); libminizinc-2.4.2/share/minizinc/std/redefinitions-2.2.1.mzn000066400000000000000000000004671360574160400236050ustar00rootroot00000000000000% This file contains redefinitions of standard builtins for version 2.2.1 % that can be overridden by solvers. /** @group flatzinc.int Constrains \a z = \(\a x ^ {\a y}\) */ predicate int_pow_fixed(var int: x, int: y, var int: z) = if y=0 then z=1 elseif y=1 then z=x else z=product([x | i in 1..y]) endif; libminizinc-2.4.2/share/minizinc/std/redefinitions-2.3.3.mzn000066400000000000000000000006371360574160400236070ustar00rootroot00000000000000% This file contains redefinitions of standard builtins for version 2.3.3 % that can be overridden by solvers. predicate float_set_in(var float: x, set of float: S) = let { array[int] of float: r1d = set_to_ranges(S); array[int,1..2] of float: r = array2d(1..length(r1d) div 2,1..2,r1d) } in exists (i in index_set_1of2(r)) ( if r[i,1]=r[i,2] then x=r[i,1] else (x>=r[i,1] /\ x<=r[i,2]) endif ); libminizinc-2.4.2/share/minizinc/std/redefinitions.mzn000066400000000000000000000001351360574160400231370ustar00rootroot00000000000000% This file contains redefinitions of standard builtins that can be overridden % by solvers. libminizinc-2.4.2/share/minizinc/std/regular.mzn000066400000000000000000000025061360574160400217420ustar00rootroot00000000000000include "fzn_regular.mzn"; include "fzn_regular_reif.mzn"; /** @group globals.extensional The sequence of values in array \a x (which must all be in the range 1..\a S) is accepted by the DFA of \a Q states with input 1..\a S and transition function \a d (which maps (1..\a Q, 1..\a S) -> 0..\a Q)) and initial state \a q0 (which must be in 1..\a Q) and accepting states \a F (which all must be in 1..\a Q). We reserve state 0 to be an always failing state. */ predicate regular(array[int] of var int: x, int: Q, int: S, array[int,int] of int: d, int: q0, set of int: F) = assert(Q > 0, "regular: 'Q' must be greater than zero", assert(S > 0, "regular: 'S' must be greater than zero", assert(index_set_1of2(d) = 1..Q /\ index_set_2of2(d) == 1..S, "regular: the transition function 'd' must be [1..Q,1..S]", assert(forall([d[i, j] in 0..Q | i in 1..Q, j in 1..S]), "regular: transition function 'd' points to states outside 0..Q", % Nb: we need the parentheses around the expression otherwise the % parser thinks it's a generator call! assert((q0 in 1..Q), "regular: start state 'q0' not in 1..Q", assert(F subset 1..Q, "regular: final states in 'F' contain states outside 1..Q", fzn_regular(x,Q,S,d,q0,F) )))))); libminizinc-2.4.2/share/minizinc/std/regular_nfa.mzn000066400000000000000000000053411360574160400225660ustar00rootroot00000000000000include "fzn_regular_nfa.mzn"; include "fzn_regular_nfa_reif.mzn"; include "fzn_regular_nfa_set.mzn"; include "fzn_regular_nfa_set_reif.mzn"; /** @group globals.extensional The sequence of values in array \a x (which must all be in the range 1..\a S) is accepted by the NFA of \a Q states with input 1..\a S and transition function \a d (which maps (1..\a Q, 1..\a S) -> set of 1..\a Q)) and initial state \a q0 (which must be in 1..\a Q) and accepting states \a F (which all must be in 1..\a Q). */ predicate regular_nfa(array[int] of var int: x, int: Q, int: S, array[int,int] of set of int: d, int: q0, set of int: F) = assert(Q > 0, "regular_nfa: 'Q' must be greater than zero", assert(S > 0, "regular_nfa: 'S' must be greater than zero", assert(index_set_1of2(d) = 1..Q /\ index_set_2of2(d) == 1..S, "regular_nfa: the transition function 'd' must be [1..Q,1..S]", assert(forall([d[i, j] subset 1..Q | i in 1..Q, j in 1..S]), "regular_nfa: transition function 'd' points to states outside 1..Q", % Nb: we need the parentheses around the expression otherwise the % parser thinks it's a generator call! assert((q0 in 1..Q), "regular: start state 'q0' not in 1..Q", assert(F subset 1..Q, "regular: final states in 'F' contain states outside 1..Q", fzn_regular_nfa(x,Q,S,d,q0,F) )))))); /** @group globals.extensional The sequence of values in array \a x (which must all be in the range \a S) is accepted by the NFA of \a Q states with input \a S and transition function \a d (which maps (1..\a Q, \a S) -> set of 1..\a Q)) and initial state \a q0 (which must be in 1..\a Q) and accepting states \a F (which all must be in 1..\a Q). */ predicate regular_nfa(array[int] of var int: x, int: Q, set of int: S, array[int,int] of set of int: d, int: q0, set of int: F) = assert(Q > 0, "regular_nfa: 'Q' must be greater than zero", assert(card(S) > 0, "regular_nfa: 'S' must be non empty", assert(S = min(S)..max(S), "regular_nfa: 'S' must be a range", assert(index_set_1of2(d) = 1..Q /\ index_set_2of2(d) == S, "regular_nfa: the transition function 'd' must be [1..Q,S]", assert(forall([d[i, j] subset 1..Q | i in 1..Q, j in S]), "regular_nfa: transition function 'd' points to states outside 1..Q", % Nb: we need the parentheses around the expression otherwise the % parser thinks it's a generator call! assert((q0 in 1..Q), "regular: start state 'q0' not in 1..Q", assert(F subset 1..Q, "regular: final states in 'F' contain states outside 1..Q", fzn_regular_nfa(x,Q,S,d,q0,F) ))))))); libminizinc-2.4.2/share/minizinc/std/regular_regexp.mzn000066400000000000000000000024241360574160400233130ustar00rootroot00000000000000include "fzn_regular_regexp.mzn"; include "regular.mzn"; /** @group globals.extensional The sequence of values in array \a x is accepted by the regular expression \a r. This constraint generates it's DFA equivalent. Regular expressions can use the following syntax: - Selection: - Concatenation: "12 34", 12 followed by 34. (Characters are assumed to be the part of the same number unless split by syntax or whitespace.) - Union: "7|11", a 7 or 11. - Groups: "7(6|8)", a 7 followed by a 6 or an 8. - Wildcard: ".", any value within the domain. - Classes: "[3-6 7]", a 3,4,5,6, or 7. - Negated classes: "[^3 5]", any value within the domain except for a 3 or a 5. - Quantifiers: - Asterisk: "12*", 0 or more times a 12. - Question mark: "5?", 0 or 1 times a 5. (optional) - Plus sign: "42+", 1 or more time a 42. - Exact: "1{3}", exactly 3 times a 1. - At least: "9{5,}", 5 or more times a 9. - Between: "7{3,5}", at least 3 times, but at most 5 times a 7. Members of enumerated types can be used in place of any integer (e.g., "A B", A followed by B). Enumerated identifiers still use whitespace for concatenation. */ predicate regular(array[int] of var int: x, string: r) = fzn_regular(x, r); libminizinc-2.4.2/share/minizinc/std/regular_set.mzn000066400000000000000000000024761360574160400226230ustar00rootroot00000000000000include "fzn_regular_set.mzn"; include "fzn_regular_set_reif.mzn"; /** @group globals.extensional The sequence of values in array \a x (which must all be in the set \a S) is accepted by the DFA of \a Q states with input \a S and transition function \a d (which maps (1..\a Q, \a S) -> 0..\a Q)) and initial state \a q0 (which must be in 1..\a Q) and accepting states \a F (which all must be in 1..\a Q). We reserve state 0 to be an always failing state. */ predicate regular(array[int] of var int: x, int: Q, set of int: S, array[int,int] of int: d, int: q0, set of int: F) = assert(Q > 0, "regular: 'Q' must be greater than zero", assert(card(S) > 0, "regular: 'S' must be non empty", assert(index_set_1of2(d) = 1..Q /\ index_set_2of2(d) == S, "regular: the transition function 'd' must be [1..Q,S]", assert(forall([d[i, j] in 0..Q | i in 1..Q, j in S]), "regular: transition function 'd' points to states outside 0..Q", % Nb: we need the parentheses around the expression otherwise the % parser thinks it's a generator call! assert((q0 in 1..Q), "regular: start state 'q0' not in 1..Q", assert(F subset 1..Q, "regular: final states in 'F' contain states outside 1..Q", fzn_regular(x,Q,S,d,q0,F) )))))); libminizinc-2.4.2/share/minizinc/std/roots.mzn000066400000000000000000000006261360574160400214500ustar00rootroot00000000000000include "fzn_roots.mzn"; include "fzn_roots_reif.mzn"; /** @group globals Requires that \a x[\p i] in \a t for all \p i in \a s */ predicate roots(array[int] of var int: x, var set of int: s, var set of int: t) = assert(ub(s) subset index_set(x), "roots: upper bound of 's' must be a subset of the index set of 'x'", fzn_roots(x,s,t) ); libminizinc-2.4.2/share/minizinc/std/roots_fn.mzn000066400000000000000000000005361360574160400221330ustar00rootroot00000000000000include "roots.mzn"; /** @group globals Returns \a s such that \a x[\p i] in \a t for all \p i in \a s */ function var set of int: roots(array[int] of var int: x, var set of int: t) :: promise_total = let { var set of index_set(x): s ::is_defined_var; constraint roots(x,s,t) ::defines_var(s); } in s; libminizinc-2.4.2/share/minizinc/std/seq_precede_chain.mzn000066400000000000000000000011311360574160400237130ustar00rootroot00000000000000include "fzn_seq_precede_chain_int.mzn"; include "fzn_seq_precede_chain_int_reif.mzn"; include "fzn_seq_precede_chain_set.mzn"; include "fzn_seq_precede_chain_set_reif.mzn"; /** @group globals.lexicographic Requires that \a i precedes \a i+1 in the array \a x for all positive \a i. */ predicate seq_precede_chain(array[int] of var int: x) = fzn_seq_precede_chain_int(x); /** @group globals.lexicographic Requires that \a i appears in a set in array \a x before \a i+1 for all positive \a i */ predicate seq_precede_chain(array[int] of var set of int: x) = fzn_seq_precede_chain_set(x); libminizinc-2.4.2/share/minizinc/std/set_member.mzn000066400000000000000000000005471360574160400224260ustar00rootroot00000000000000include "fzn_set_member.mzn"; include "fzn_set_member_reif.mzn"; %-----------------------------------------------------------------------------% % Requires that 'y' occurs in the array or set 'x'. %-----------------------------------------------------------------------------% predicate set_member(var set of int: x, var int: y) = fzn_set_member(x, y); libminizinc-2.4.2/share/minizinc/std/sliding_sum.mzn000066400000000000000000000005361360574160400226170ustar00rootroot00000000000000include "fzn_sliding_sum.mzn"; include "fzn_sliding_sum_reif.mzn"; /** @group globals Requires that in each subsequence \a vs[\p i], ..., \a vs[\p i + \a seq - 1] the sum of the values belongs to the interval [\a low, \a up]. */ predicate sliding_sum(int: low, int: up, int: seq, array[int] of var int: vs) = fzn_sliding_sum(low, up, seq, vs); libminizinc-2.4.2/share/minizinc/std/sort.mzn000066400000000000000000000006301360574160400212640ustar00rootroot00000000000000include "fzn_sort.mzn"; include "fzn_sort_reif.mzn"; /** @group globals.sort Requires that the multiset of values in \a x are the same as the multiset of values in \a y but \a y is in sorted order. */ predicate sort(array[int] of var int: x, array[int] of var int: y) = assert(card(index_set(x)) == card(index_set(y)), "sort: x and y must be same sized arrays", fzn_sort(x,y) ); libminizinc-2.4.2/share/minizinc/std/sort_fn.mzn000066400000000000000000000005311360574160400217470ustar00rootroot00000000000000include "sort.mzn"; /** @group globals.sort Return a multiset of values that is the same as the multiset of values in \a x but in sorted order. */ function array[int] of var int: sort(array[int] of var int: x) ::promise_total = let { array[1..length(x)] of var lb_array(x)..ub_array(x): y; constraint sort(x,y); } in y; libminizinc-2.4.2/share/minizinc/std/span.mzn000066400000000000000000000007661360574160400212500ustar00rootroot00000000000000include "fzn_span.mzn"; include "fzn_span_reif.mzn"; /** @group globals.scheduling Span constraint for optional tasks. Task (\a s0,\a d0) spans the optional tasks (\a s[\p i],\a d[\p i]) in the array arguments. */ predicate span(var opt int: s0, var int: d0, array[int] of var opt int: s, array[int] of var int: d) = assert(index_set(s) = index_set(d), "span: index sets of third and fourth argument must be identical", fzn_span(s0,d0,s,d) ); libminizinc-2.4.2/share/minizinc/std/stdlib.mzn000066400000000000000000001550101360574160400215610ustar00rootroot00000000000000%-----------------------------------------------------------------------------% % MiniZinc standard library. %-----------------------------------------------------------------------------% % This file contains declarations of all functions, predicates and annotations % available in the base MiniZinc language. /*** @groupdef MAIN The MiniZinc library */ /*** @groupdef annotations Annotations These annotations control evaluation and solving behaviour. */ /*** @groupdef annotations.general General annotations */ /** @group annotations.general Declare function as total, i.e. it does not put any constraints on its arguments. */ annotation promise_total; /** @group annotations.general Declare that expression may have undefined result (to avoid warnings) */ annotation maybe_partial; /** @group annotations.general Declare that the annotated variable should be added to the output of the model. This annotation only has an effect when the model does not have an output item. */ annotation add_to_output; /** @group annotations.general Declare that the annotated variable should be only used for output. This annotation can be used to define variables that are required for solution checkers, or that are necessary for the output item. The annotated variable must be par. */ annotation output_only; /** @group annotations.general Declare that the annotated variable is required for checking solutions. */ annotation mzn_check_var; /** @group annotations.general Declare that the annotated variable is required for checking solutions and has an enum type. */ annotation mzn_check_enum_var(set of int); /** @group annotations.general Declare a name for the annotated expression. */ annotation mzn_expression_name(string); /** @group annotations.general Declare a name for the annotated constraint. */ annotation mzn_constraint_name(string); /** @group annotations.general State that a function is deprecated. */ annotation mzn_deprecated(string: version, string: explanation); function $T: mzn_deprecate(string: name, string: version, string: msg, $T: x); function var $T: mzn_deprecate(string: name, string: version, string: msg, var $T: x); function var opt $T: mzn_deprecate(string: name, string: version, string: msg, var opt $T: x); function array[$U] of $T: mzn_deprecate(string: name, string: version, string: msg, array[$U] of $T: x); function array[$U] of var $T: mzn_deprecate(string: name, string: version, string: msg, array[$U] of var $T: x); function array[$U] of var opt $T: mzn_deprecate(string: name, string: version, string: msg, array[$U] of var opt $T: x); /** @group annotations.general Declare the annotated variable as being functionally defined. This annotation is introduced into FlatZinc code by the compiler. */ annotation is_defined_var; /** @group annotations.general Declare a variable as being introduced by the compiler. */ annotation var_is_introduced; /** @group annotations.general Declare variable: \a c as being functionally defined by the annotated constraint. This annotation is introduced into FlatZinc code by the compiler. */ annotation defines_var(var $t: c); /** @group annotations.general Declare that the annotated array should be printed by the solver with the given index sets \a a. This annotation is introduced into FlatZinc code by the compiler. */ annotation output_array(array[$u] of set of int:a); /** @group annotations.general Declare that the annotated variable should be printed by the solver. This annotation is introduced into FlatZinc code by the compiler. */ annotation output_var; /** @group annotations.general Declare that the annotated expression is used to map an expression back from FlatZinc to MiniZinc. */ annotation is_reverse_map; /** @group annotations.general Document the function or variable declaration item with the string \a s. */ annotation doc_comment(string: s); /** @group annotations.general Representation of the call-stack when the annotated item was introduced, as a string \a s. Can be used to uniquely identify variables and constraints across different compilations of a model that may have different names. This annotations is introduced into FlatZinc code by the compiler and is retained if --keep-paths argument is used. */ annotation mzn_path(string: s); /** @group annotations.general With debug build of mzn2fzn, call MiniZinc::mzn_break_here when flattening this expression to make debugging easier. This annotation is ignored by the release build.*/ annotation mzn_break_here; /** @group annotations.general Used to attach a name \a s to an expression, this should also propagate to any sub-expressions or decomposition of the annotated expression. String annotations on expressions are re-written as expression_name annotations */ annotation expression_name(string: s); /** @group annotations.general Used to attach a name \a s to a constraint and its decomposition. String annotations on constraint keywords are re-written as constraint_name annotations */ annotation constraint_name(string: s); /** @group annotations.general Used internally by the compiler */ annotation mzn_rhs_from_assignment; /** @group annotations.general Marks a constraint as a recorded domain changing constraint (when mzn2fzn called with -g flag */ annotation domain_change_constraint; /*** @groupdef annotations.prop Propagation strength annotations */ /** @group annotations.prop Annotate a constraint to use domain propagation */ annotation domain; /** @group annotations.prop Annotate a constraint to use bounds propagation */ annotation bounds; /*** @groupdef annotations.search Search annotations */ /** @group annotations.search Sequentially perform the searches specified in array \a s */ annotation seq_search(array[int] of ann: s); /** @group annotations.search Specify search on variables \a x, with variable selection strategy \a select, value choice strategy \a choice, and exploration strategy \a explore. If \a x is a multi-dimensional array, it is coerced to one-dimensional in row-major order (as with the array1d function). */ annotation int_search( array[$X] of var int: x, ann: select, ann: choice, ann: explore, ); /** @group annotations.search Specify search on variables \a x, with variable selection strategy \a select, and value choice strategy \a choice. If \a x is a multi-dimensional array, it is coerced to one-dimensional in row-major order (as with the array1d function). */ annotation int_search( array[$X] of var int: x, ann: select, ann: choice ) = int_search(x,select,choice,complete); /** @group annotations.search Specify search on variables \a x, with variable selection strategy \a select, value choice strategy \a choice, and exploration strategy \a explore. If \a x is a multi-dimensional array, it is coerced to one-dimensional in row-major order (as with the array1d function). */ annotation bool_search( array[$X] of var bool: x, ann: select, ann: choice, ann: explore ); /** @group annotations.search Specify search on variables \a x, with variable selection strategy \a select, and value choice strategy \a choice. If \a x is a multi-dimensional array, it is coerced to one-dimensional in row-major order (as with the array1d function). */ annotation bool_search( array[$X] of var bool: x, ann: select, ann: choice ) = bool_search(x,select,choice,complete); /** @group annotations.search Specify search on variables \a x, with precision \a prec, variable selection strategy \a select, value choice strategy \a choice, and exploration strategy \a explore. If \a x is a multi-dimensional array, it is coerced to one-dimensional in row-major order (as with the array1d function). */ annotation float_search( array[$X] of var float: x, float: prec, ann: select, ann: choice, ann: explore ); /** @group annotations.search Specify search on variables \a x, with precision \a prec, variable selection strategy \a select, and value choice strategy \a choice. If \a x is a multi-dimensional array, it is coerced to one-dimensional in row-major order (as with the array1d function). */ annotation float_search( array[$X] of var float: x, float: prec, ann: select, ann: choice ) = float_search(x,prec,select,choice,complete); /** @group annotations.search Specify search on variables \a x, with variable selection strategy \a select, value choice strategy \a choice, and exploration strategy \a explore. If \a x is a multi-dimensional array, it is coerced to one-dimensional in row-major order (as with the array1d function). */ annotation set_search( array[$X] of var set of int: x, ann: select, ann: choice, ann: explore ); /** @group annotations.search Specify search on variables \a x, with variable selection strategy \a select, and value choice strategy \a choice. If \a x is a multi-dimensional array, it is coerced to one-dimensional in row-major order (as with the array1d function). */ annotation set_search( array[$X] of var set of int: x, ann: select, ann: choice ) = set_search(x,select,choice,complete); /*** @groupdef annotations.search.varsel Variable selection annotations */ /** @group annotations.search.varsel Search variables in the given order */ annotation input_order; /** @group annotations.search.varsel Choose the variable with the smallest domain */ annotation first_fail; /** @group annotations.search.varsel Choose the variable with the largest domain */ annotation anti_first_fail; /** @group annotations.search.varsel Choose the variable with the smallest value in its domain */ annotation smallest; /** @group annotations.search.varsel Choose the variable with the largest value in its domain */ annotation largest; /** @group annotations.search.varsel Choose the variable with the largest number of attached constraints */ annotation occurrence; /** @group annotations.search.varsel Choose the variable with the smallest domain, breaking ties using the number of attached constraints */ annotation most_constrained; /** @group annotations.search.varsel Choose the variable with largest difference between the two smallest values in its domain */ annotation max_regret; /** @group annotations.search.varsel Choose the variable with largest domain, divided by the number of attached constraints weighted by how often they have caused failure */ annotation dom_w_deg; /** @group annotations.search.varsel Choose the variable with the highest impact so far during the search */ annotation impact; /*** @groupdef annotations.search.choice Value choice annotations */ /** @group annotations.search.choice Assign values in ascending order */ annotation indomain; /** @group annotations.search.choice Assign the smallest value in the domain */ annotation indomain_min; /** @group annotations.search.choice Assign the largest value in the domain */ annotation indomain_max; /** @group annotations.search.choice Assign the value in the domain closest to the mean of its current bounds */ annotation indomain_middle; /** @group annotations.search.choice Assign the middle value in the domain */ annotation indomain_median; /** @group annotations.search.choice Assign a random value from the domain */ annotation indomain_random; /** @group annotations.search.choice Bisect the domain, excluding the upper half first */ annotation indomain_split; /** @group annotations.search.choice Bisect the domain, randomly selecting which half to exclude first */ annotation indomain_split_random; /** @group annotations.search.choice Bisect the domain, excluding the lower half first */ annotation indomain_reverse_split; /** @group annotations.search.choice If the domain consists of several contiguous intervals, reduce the domain to the first interval. Otherwise bisect the domain. */ annotation indomain_interval; /** @group annotations.search.choice Exclude the smallest value from the domain */ annotation outdomain_min; /** @group annotations.search.choice Exclude the largest value from the domain */ annotation outdomain_max; /** @group annotations.search.choice Exclude the middle value from the domain */ annotation outdomain_median; /** @group annotations.search.choice Exclude a random value from the domain */ annotation outdomain_random; /*** @groupdef annotations.search.explore Exploration strategy annotations */ /** @group annotations.search.explore Perform a complete search */ annotation complete; /*** @groupdef annotations.search.restart Restart annotations */ /** @group annotations.search.restart Restart with Luby sequence scaled by \a scale */ annotation restart_luby(int: scale); /** @group annotations.search.restart Restart with geometric sequence with parameters \a base and \a scale */ annotation restart_geometric(float: base, int: scale); /** @group annotations.search.restart Restart with linear sequence scaled by \a scale */ annotation restart_linear(int: scale); /** @group annotations.search.restart Restart after constant number of nodes \a scale */ annotation restart_constant(int: scale); /** @group annotations.search.restart Do not restart */ annotation restart_none; /*** @groupdef annotations.warmstart Warm start annotations To be put on the solve item, similar to search annotations. A variable can be mentioned several times and in different annotations but only one of the values is taken */ /** @group annotations.warmstart Specify an array \a w of warm_start annotations or other warm_start_array annotations. Can be useful to keep the annotation order in FlatZinc for manual updating. Note: if you have search annotations as well, put warm_starts into seq_search in order to have precedence between both, which may matter. */ annotation warm_start_array( array[int] of ann: w ); /** @group annotations.warmstart Specify warm start values \a v for an array of booleans \a x */ annotation warm_start( array[int] of var bool: x, array[int] of bool: v ); /** @group annotations.warmstart Specify warm start values \a v for an array of integers \a x */ annotation warm_start( array[int] of var int: x, array[int] of int: v ); /** @group annotations.warmstart Specify warm start values \a v for an array of floats \a x */ annotation warm_start( array[int] of var float: x, array[int] of float: v ); /** @group annotations.warmstart Specify warm start values \a v for an array of sets \a x */ annotation warm_start( array[int] of var set of int: x, array[int] of set of int: v ); /*** @groupdef annotations.warmstart.optvals Warm start annotations with optional values The value arrays can contain <> elements (absent values). The following decompositions eliminate those elements because FlatZinc 1.6 does not support optionals. */ /** @group annotations.warmstart.optvals Specify warm start values \a v for an array of booleans \a x */ annotation warm_start( array[int] of var bool: x, array[int] of opt bool: v ) = if 0==length(x) \/ 0==length(v) then warm_start( x, [] ) else warm_start( [ x[i] | i in index_set(x) where i-min(index_set(x))+min(index_set(v))>length(v) \/ occurs( v[ i-min(index_set(x))+min(index_set(v)) ] ) ], [ deopt(v[i]) | i in index_set(v) where occurs(v[i]) ] ) endif; /** @group annotations.warmstart.optvals Specify warm start values \a v for an array of integers \a x */ annotation warm_start( array[int] of var int: x, array[int] of opt int: v ) = if 0==length(x) \/ 0==length(v) then warm_start( x, [] ) else warm_start( [ x[i] | i in index_set(x) where i-min(index_set(x))+min(index_set(v))>length(v) \/ occurs( v[ i-min(index_set(x))+min(index_set(v)) ] ) ], [ deopt(v[i]) | i in index_set(v) where occurs(v[i]) ] ) endif; /** @group annotations.warmstart.optvals Specify warm start values \a v for an array of floats \a x */ annotation warm_start( array[int] of var float: x, array[int] of opt float: v ) = if 0==length(x) \/ 0==length(v) then warm_start( x, [] ) else warm_start( [ x[i] | i in index_set(x) where i-min(index_set(x))+min(index_set(v))>length(v) \/ occurs( v[ i-min(index_set(x))+min(index_set(v)) ] ) ], [ deopt(v[i]) | i in index_set(v) where occurs(v[i]) ] ) endif; /** @group annotations.warmstart.optvals Specify warm start values \a v for an array of sets \a x */ annotation warm_start( array[int] of var set of int: x, array[int] of opt set of int: v ) = if 0==length(x) \/ 0==length(v) then warm_start( x, [] ) else warm_start( [ x[i] | i in index_set(x) where i-min(index_set(x))+min(index_set(v))>length(v) \/ occurs( v[ i-min(index_set(x))+min(index_set(v)) ] ) ], [ deopt(v[i]) | i in index_set(v) where occurs(v[i]) ] ) endif; /*** @groupdef optiontypes Option type support These functions and predicates implement the standard library for working with option types. Note that option type support is still incomplete. */ /** @group optiontypes Return value of \a x if \a x is not absent. Aborts when evaluated on absent value. */ function $T: deopt(opt $T: x); /** @group optiontypes Return value \a x unchanged (since \a x is guaranteed to be non-optional). */ function var $T: deopt(var $T: x) = x; /** @group optiontypes Test if \a x is not absent (always returns true) */ test occurs(var $T: x) = true; /** @group optiontypes Test if \a x is not absent */ test occurs(opt $T: x); /** @group optiontypes Test if \a x is absent (always returns false) */ test absent(var $T: x) = false; /** @group optiontypes Test if \a x is absent */ test absent(opt $T: x) = not occurs(x); /*** @groupdef optiontypes.bool Option type support for Booleans */ /** @group optiontypes.bool True iff \a x is not absent */ function var bool : occurs(var opt bool: x) ::promise_total = occurs_bool(x); function bool : occurs_bool(opt bool: x) ::promise_total = occurs(x); function bool : occurs_bool(var bool: x) ::promise_total = true; function var bool : occurs_bool(var opt bool: x) ::promise_total = let { var bool : b = occurs_internal_bool(x); var bool : dx = deopt_internal_bool(x); constraint (x = reverse_map_var_opt_bool(b,dx)) :: is_reverse_map; } in b; /** @group optiontypes.bool Return value of \a x (assumes that \a x is not absent) */ function var bool : deopt(var opt bool : x) ::promise_total = deopt_bool(x); function bool : deopt_bool(opt bool : x) ::promise_total = deopt(x); function var bool : deopt_bool(var bool : x) ::promise_total = x; function var bool : deopt_bool(var opt bool : x) ::promise_total = let { var bool : b = occurs_internal_bool(x); var bool : dx = deopt_internal_bool(x); constraint (x = reverse_map_var_opt_bool(b,dx)) :: is_reverse_map; } in dx; /** @group optiontypes.bool True iff \a x is absent */ predicate absent(var opt bool: x) = not occurs(x); function var bool: occurs_internal_bool(var opt bool: x) ::promise_total = let { var bool : b; } in b; function var bool : deopt_internal_bool(var opt bool : x) ::promise_total = let { var bool: y } in y; function var opt bool: reverse_map_var_opt_bool(var bool: occ, var bool: d); function opt bool: reverse_map_var_opt_bool(bool: occ, bool: d) ::promise_total = if occ then d else <> endif; predicate bool_opt_eq(var opt bool: x, var opt bool: y) = deopt(x)=deopt(y) /\ occurs(x)=occurs(y); /** @group optiontypes.bool True iff both \a b0 and \a b1 are absent or both are present and have the same value. */ predicate bool_eq(var opt bool: b0, var opt bool: b1) = (absent(b0) /\ absent(b1)) \/ (occurs(b0) /\ occurs(b1) /\ deopt(b0)=deopt(b1)); /** @group optiontypes.bool True iff \a b0 occurs and is equal to \a b1 */ predicate bool_eq(var opt bool: b0, var bool: b1) = occurs(b0) /\ deopt(b0)=b1; /** @group optiontypes.bool True iff \a b1 occurs and is equal to \a b0 */ predicate bool_eq(var bool: b0, var opt bool: b1) = occurs(b1) /\ deopt(b1)=b0; /** @group optiontypes.bool True iff for any \p i, \a x[i] is absent or true */ predicate forall (array[int] of var opt bool: x) = forall ([absent(x[i]) \/ deopt(x[i]) | i in index_set(x)]); /** @group optiontypes.bool True iff for at least one \p i, \a x[i] occurs and is true */ predicate exists (array[int] of var opt bool: x) = exists ([occurs(x[i]) /\ deopt(x[i]) | i in index_set(x)]); /** @group optiontypes.bool True iff \a x is absent or false */ function var bool: 'not'(var opt bool: x) = absent(x) \/ not deopt(x); /** @group optiontypes.bool Return absent if \a idx is absent, otherwise return \a x[\a idx] */ function var opt bool: element(var opt int: idx, array[int] of var bool: x) = if absent(idx) then <> else element(deopt(idx),x) endif; /** @group optiontypes.bool Return absent if \a idx1 or \a idx2 is absent, otherwise return \a x[\a idx1, \a idx2] */ function var opt bool: element(var opt int: idx1, var opt int: idx2, array[int,int] of var bool: x) = if absent(idx1) \/ absent(idx2) then <> else element(deopt(idx1),deopt(idx2),x) endif; /** @group optiontypes.bool Return \a x[\a idx] */ function var opt bool: element(var int: idx, array[int] of var opt bool: x) = let { var opt bool: r; constraint occurs(r) = element(idx,array1d(index_set(x),[occurs(x[i]) | i in index_set(x)])); constraint deopt(r) = element(idx,array1d(index_set(x),[deopt(x[i]) | i in index_set(x)])); } in r; /** @group optiontypes.bool Return \a x[\a idx1, \a idx2] */ function var opt bool: element(var int: idx1, var int: idx2, array[int,int] of var opt bool: x) = let { var opt bool: r; constraint occurs(r) = element(idx1,idx2, array2d(index_set_1of2(x),index_set_2of2(x),[occurs(x[i,j]) | i in index_set_1of2(x), j in index_set_2of2(x)])); constraint deopt(r) = element(idx1,idx2, array2d(index_set_1of2(x),index_set_2of2(x),[deopt(x[i,j]) | i in index_set_1of2(x), j in index_set_2of2(x)])); } in r; /** @group optiontypes.bool Return absent if \a idx is absent, otherwise return \a x[\a idx] */ function var opt bool: element(var opt int: idx, array[int] of var opt bool: x) = if absent(idx) then <> else element(deopt(idx),x) endif; /** @group optiontypes.bool Return absent if \a idx1 or \a idx2 is absent, otherwise return \a x[\a idx1, \a idx2] */ function var opt bool: element(var opt int: idx1, var opt int: idx2, array[int,int] of var opt bool: x) = if absent(idx1) \/ absent(idx2) then <> else element(deopt(idx1),deopt(idx2),x) endif; /** @group optiontypes.bool Search annotation for optional Boolean variables */ annotation bool_search(array[int] of var opt bool: x, ann: a1, ann: a2, ann: a3) = bool_search([if occurs(x[i]) then deopt(x[i]) else false endif | i in index_set(x)],a1,a2,a3); /** @group optiontypes.bool Search annotation for optional Boolean variables */ annotation bool_search(array[int] of var opt bool: x, ann: a1, ann: a2) = bool_search([if occurs(x[i]) then deopt(x[i]) else false endif | i in index_set(x)],a1,a2); /*** @groupdef optiontypes.int Option type support for integers */ /** @group optiontypes.int True iff \a x is not absent */ function var bool : occurs(var opt int : x) ::promise_total = occurs_int(x); function bool : occurs_int(opt int : x) ::promise_total = occurs(x); function bool : occurs_int(var int : x) ::promise_total = true; function var bool : occurs_int(var opt int : x) ::promise_total = let { var bool : b = occurs_internal_int(x); var int : dx = deopt_internal_int(x); constraint (x = reverse_map_var_opt_int(b,dx)) :: is_reverse_map; } in b; function var bool : occurs_int(var opt bool : x) ::promise_total = occurs(x); function bool : occurs_int(opt bool : x) ::promise_total = occurs(x); function bool : occurs_int(var bool : x) ::promise_total = true; /** @group optiontypes.int Return value of \a x (assumes that \a x is not absent) */ function var $$E : deopt(var opt $$E : x) ::promise_total = deopt_int(x); function var opt int: if_b_else_absent(var bool: b, var int: x) ::promise_total = let { var opt dom(x): y; constraint not occurs(y); } in if b then x else y endif; function var int: if_b_else_zero(var bool: b, var int: x) ::promise_total = if b then x else 0 endif; function int : deopt_int(opt int : x) ::promise_total = deopt(x); function var int : deopt_int(var int : x) ::promise_total = x; function var int : deopt_int(var opt int : x) ::promise_total = let { var bool : b = occurs_internal_int(x); var int : dx = deopt_internal_int(x); constraint (x = reverse_map_var_opt_int(b,dx)) :: is_reverse_map; } in dx; function var bool : deopt_int(var opt bool : x) ::promise_total = deopt(x); function var bool : deopt_int(var bool : x) ::promise_total = x; function bool : deopt_int(opt bool : x) ::promise_total = deopt(x); /** @group optiontypes.int True iff \a x is absent */ function var bool: absent(var opt int: x) ::promise_total = not occurs(x); function var bool: occurs_internal_int(var opt int: x) ::promise_total = let { var bool : b; } in b; function var int : deopt_internal_int(var opt int : x) ::promise_total = let { var lb(x)..ub(x): y } in y; function var opt int: reverse_map_var_opt_int(var bool: occ, var int: d); function opt int: reverse_map_var_opt_int(bool: occ, int: d) ::promise_total = if occ then d else <> endif; predicate var_dom(var opt int:x, set of int: s) = let { var int: dx = deopt(x); set of int: new_dom = dom(dx) intersect s; } in if new_dom = {} then absent(x) else dx in new_dom endif; predicate var_dom(array[$T] of var opt int: x, set of int: d) = let { array[int] of var opt int: xx = array1d(x) } in forall (i in index_set(xx)) (var_dom(xx[i],d)); predicate int_opt_eq(var opt int: x, var opt int: y) = deopt(x) = deopt(y) /\ occurs(x) = occurs(y); /** @group optiontypes.int Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is greater than the value of \a y. */ function var bool: '>'(var opt int: x, var opt int: y) = absent(x) \/ absent(y) \/ deopt(x) > deopt(y); /** @group optiontypes.int Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is greater than or equal to the value of \a y. */ function var bool: '>='(var opt int: x, var opt int: y) = absent(x) \/ absent(y) \/ deopt(x) >= deopt(y); /** @group optiontypes.int Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is less than the value of \a y. */ function var bool: '<'(var opt int: x, var opt int: y) = absent(x) \/ absent(y) \/ deopt(x) < deopt(y); /** @group optiontypes.int Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is less than or equal to the value of \a y. */ function var bool: '<='(var opt int: x, var opt int: y) = absent(x) \/ absent(y) \/ deopt(x) <= deopt(y); /** @group optiontypes.int Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is greater than the value of \a y. */ function bool: '>'(opt int: x, opt int: y) = absent(x) \/ absent(y) \/ deopt(x) > deopt(y); /** @group optiontypes.int Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is greater than or equal to the value of \a y. */ function bool: '>='(opt int: x, opt int: y) = absent(x) \/ absent(y) \/ deopt(x) >= deopt(y); /** @group optiontypes.int Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is less than the value of \a y. */ function bool: '<'(opt int: x, opt int: y) = absent(x) \/ absent(y) \/ deopt(x) < deopt(y); /** @group optiontypes.int Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is less than or equal to the value of \a y. */ function bool: '<='(opt int: x, opt int: y) = absent(x) \/ absent(y) \/ deopt(x) <= deopt(y); /** @group optiontypes.int Return minimum of elements in \a x that are not absent, or absent if all elements in \a x are absent. */ function var opt int: min(array[int] of var opt int: x) ::promise_total = let { var opt lb_array(x)..ub_array(x): m; var lb_array(x)..ub_array(x): xmax; constraint if ub(xmax) != infinity then xmax = ub(xmax) else forall (i in index_set(x)) (xmax >= deopt(x[i])) endif; constraint occurs(m) <-> exists (i in index_set(x)) (occurs(x[i])); constraint occurs(m) -> deopt(m) = min([if occurs(xi) then deopt(xi) else xmax endif | xi in x]); } in m; /** @group optiontypes.int Return maximum of elements in \a x that are not absent, or absent if all elements in \a x are absent. */ function var opt int: max(array[int] of var opt int: x) ::promise_total = let { var opt lb_array(x)..ub_array(x): m; var lb_array(x)..ub_array(x): xmin; constraint if lb(xmin) != -infinity then xmin = lb(xmin) else forall (i in index_set(x)) (xmin <= deopt(x[i])) endif; constraint occurs(m) <-> exists (i in index_set(x)) (occurs(x[i])); constraint occurs(m) -> deopt(m) = max([if occurs(xi) then deopt(xi) else xmin endif | xi in x]); } in m; /** @group optiontypes.int Weak addition. Return sum of \a x and \a y if both are present, otherwise return absent. */ function var opt int: '~+'(var opt int: x, var opt int: y) ::promise_total = let { int: l = if lb(x)=-infinity \/ lb(y)=-infinity then -infinity else lb(x)+lb(y) endif; int: u = if ub(x)=infinity \/ ub(y)=infinity then infinity else ub(x)+ub(y) endif; var opt l..u: result; constraint absent(x) \/ absent(y) -> result = <>; constraint absent(x) \/ absent(y) \/ result = deopt(x)+deopt(y); } in result; /** @group optiontypes.int Weak subtraction. Return difference of \a x and \a y if both are present, otherwise return absent. */ function var opt int: '~-'(var opt int: x, var opt int: y) ::promise_total = let { int: l = if lb(x)=-infinity \/ ub(y)=infinity then -infinity else lb(x)-ub(y) endif; int: u = if ub(x)=infinity \/ lb(y)=-infinity then infinity else ub(x)-lb(y) endif; var opt l..u: result; constraint absent(x) \/ absent(y) -> result = <>; constraint absent(x) \/ absent(y) \/ result = deopt(x)-deopt(y); } in result; /** @group optiontypes.int Weak multiplication. Return product of \a x and \a y if both are present, otherwise return absent. */ function var opt int: '~*'(var opt int: x, var opt int: y) ::promise_total = if absent(x) \/ absent(y) then <> else deopt(x)*deopt(y) endif; /** @group optiontypes.int Weak equality. True if either \a x or \a y are absent, or present and equal.*/ function var bool: '~='(var opt int: x, var opt int: y) ::promise_total = absent(x) \/ absent(y) \/ deopt(x)=deopt(y); /** @group optiontypes.int Return optional 0/1 integer that is absent iff \a x is absent, and 1 iff \a x occurs and is true. */ function var opt int: bool2int(var opt bool: x) ::promise_total = let { var opt 0..1: xi; constraint absent(xi)=absent(x); constraint deopt(xi)=bool2int(deopt(x)); } in xi; /** @group optiontypes.int True iff both \a x and \a y are absent or both are present and have the same value. */ predicate int_eq(var opt int: x, var opt int: y) = (absent(x) /\ absent(y)) \/ (occurs(x) /\ occurs(y) /\ (deopt(x)=deopt(y))::maybe_partial); /** @group optiontypes.int True iff only one of \a x and \a y is absent or both are present and have different values. */ predicate int_ne(var opt int : x, var opt int : y) = (absent(x) != absent(y)) \/ (occurs(x) /\ occurs(y) /\ (deopt(x)!=deopt(y))::maybe_partial); /** @group optiontypes.int Optional addition. Return sum of \a x and \a y, with absent replaced by 0. */ function var int: '+'(var opt int: x, var opt int: y) ::promise_total = if occurs(x) then deopt(x) else 0 endif + if occurs(y) then deopt(y) else 0 endif; /** @group optiontypes.int Optional addition. Return sum of \a x and \a y, with absent replaced by 0. */ function int: '+'(opt int: x, opt int: y) ::promise_total = if occurs(x) then deopt(x) else 0 endif + if occurs(y) then deopt(y) else 0 endif; /** @group optiontypes.int Optional subtraction. Return difference of \a x and \a y, with absent replaced by 0. */ function var int: '-'(var opt int: x, var opt int: y) ::promise_total = if occurs(x) then deopt(x) else 0 endif - if occurs(y) then deopt(y) else 0 endif; /** @group optiontypes.int Optional subtraction. Return difference of \a x and \a y, with absent replaced by 0. */ function int: '-'(opt int: x, opt int: y) ::promise_total = if occurs(x) then deopt(x) else 0 endif - if occurs(y) then deopt(y) else 0 endif; /** @group optiontypes.int Optional multiplication. Return product of \a x and \a y, with absent replaced by 1. */ function var int: '*'(var opt int: x, var opt int: y) ::promise_total = if occurs(x) then deopt(x) else 1 endif * if occurs(y) then deopt(y) else 1 endif; /** @group optiontypes.int Optional multiplication. Return product of \a x and \a y, with absent replaced by 1. */ function int: '*'(opt int: x, opt int: y) ::promise_total = if occurs(x) then deopt(x) else 1 endif * if occurs(y) then deopt(y) else 1 endif; /** @group optiontypes.int Optional division. Return \a x div \a y, with absent replaced by 1. */ function var int: 'div'(var opt int: x, var opt int: y) ::promise_total = if occurs(x) then deopt(x) else 1 endif div if occurs(y) then deopt(y) else 1 endif; /** @group optiontypes.int Optional division. Return \a x div \a y, with absent replaced by 1. */ function int: 'div'(opt int: x, opt int: y) ::promise_total = if occurs(x) then deopt(x) else 1 endif div if occurs(y) then deopt(y) else 1 endif; /** @group optiontypes.int Optional modulo. Return \a x mod \a y, with absent replaced by 1. */ function var int: 'mod'(var opt int: x, var opt int: y) ::promise_total = if occurs(x) then deopt(x) else 1 endif mod if occurs(y) then deopt(y) else 1 endif; /** @group optiontypes.int Optional modulo. Return \a x mod \a y, with absent replaced by 1. */ function int: 'mod'(opt int: x, opt int: y) ::promise_total = if occurs(x) then deopt(x) else 1 endif mod if occurs(y) then deopt(y) else 1 endif; /** @group optiontypes.int Return sum of non-absent elements of \a x. */ function var int: sum(array[int] of var opt int: x) = sum (i in index_set(x)) (let { var int: dx = deopt(x[i]) } in if occurs(x[i]) then dx else 0 endif); /** @group optiontypes.int Return sum of non-absent elements of \a x. */ function int: sum(array[int] of opt int: x) = sum (i in index_set(x)) (if occurs(x[i]) then deopt(x[i]) else 0 endif); /** @group optiontypes.int Return product of non-absent elements of \a x. */ function var int: product(array[int] of var opt int: x) = product (i in index_set(x)) (let { var int: dx = deopt(x[i]) } in if occurs(x[i]) then dx else 1 endif); /** @group optiontypes.int Return product of non-absent elements of \a x. */ function int: product(array[int] of opt int: x) = product (i in index_set(x)) (if occurs(x[i]) then deopt(x[i]) else 1 endif); /** @group optiontypes.int Return absent if \a idx is absent, otherwise return \a x[\a idx] */ function var opt int: element(var opt int: idx, array[int] of var int: x) = if absent(idx) then <> else element(deopt(idx),x) endif; /** @group optiontypes.int Return absent if \a idx1 or \a idx2 is absent, otherwise return \a x[\a idx1, \a idx2] */ function var opt int: element(var opt int: idx1, var opt int: idx2, array[int,int] of var int: x) = if absent(idx1) \/ absent(idx2) then <> else element(deopt(idx1),deopt(idx2),x) endif; /** @group optiontypes.int Return \a x[\a idx] */ function var opt int: element(var int: idx, array[int] of var opt int: x) = let { var opt int: r; constraint occurs(r) = element(idx,array1d(index_set(x),[occurs(x[i]) | i in index_set(x)])); constraint deopt(r) = element(idx,array1d(index_set(x),[deopt(x[i]) | i in index_set(x)])); } in r; /** @group optiontypes.int Return \a x[\a idx1, \a idx2] */ function var opt int: element(var int: idx1, var int: idx2, array[int,int] of var opt int: x) = let { var opt int: r; constraint occurs(r) = element(idx1,idx2, array2d(index_set_1of2(x),index_set_2of2(x),[occurs(x[i,j]) | i in index_set_1of2(x), j in index_set_2of2(x)])); constraint deopt(r) = element(idx1,idx2, array2d(index_set_1of2(x),index_set_2of2(x),[deopt(x[i,j]) | i in index_set_1of2(x), j in index_set_2of2(x)])); } in r; /** @group optiontypes.int Return absent if \a idx is absent, otherwise return \a x[\a idx] */ function var opt int: element(var opt int: idx, array[int] of var opt int: x) = if absent(idx) then <> else element(deopt(idx),x) endif; /** @group optiontypes.int Return absent if \a idx1 or \a idx2 is absent, otherwise return \a x[\a idx1, \a idx2] */ function var opt int: element(var opt int: idx1, var opt int: idx2, array[int,int] of var opt int: x) = if absent(idx1) \/ absent(idx2) then <> else element(deopt(idx1),deopt(idx2),x) endif; /** @group optiontypes.int Search annotation for optional integer variables */ annotation int_search(array[int] of var opt int: x, ann: a1, ann: a2, ann: a3) = int_search([if occurs(x[i]) then deopt(x[i]) else 0 endif | i in index_set(x)],a1,a2,a3); /** @group optiontypes.int Search annotation for optional integer variables */ annotation int_search(array[int] of var opt int: x, ann: a1, ann: a2) = int_search([if occurs(x[i]) then deopt(x[i]) else 0 endif | i in index_set(x)],a1,a2); /* Internal function used to optimize over option type objective */ function var int: objective_deopt_(var opt int: x, bool: direction) = let { int: worst = if direction then lb(x)-1 else ub(x)+1 endif; } in if occurs(x) then deopt(x) else worst endif; /*** @groupdef optiontypes.float Option type support for floats */ /** @group optiontypes.float True iff \a x is not absent */ function var bool : occurs(var opt float : x) ::promise_total = occurs_float(x); function bool : occurs_float(opt float : x) ::promise_total = occurs(x); function bool : occurs_float(opt int : x) ::promise_total = occurs(x); function bool : occurs_float(opt bool : x) ::promise_total = occurs(x); function bool : occurs_float(var float : x) ::promise_total = true; function var bool : occurs_float(var opt float : x) ::promise_total = let { var bool : b = occurs_internal_float(x); var float : dx = deopt_internal_float(x); constraint (x = reverse_map_var_opt_float(b,dx)) :: is_reverse_map; } in b; function var bool : occurs_float(var opt int : x) ::promise_total = occurs_int(x); function bool : occurs_float(var int : x) ::promise_total = true; function var bool : occurs_float(var opt bool : x) ::promise_total = occurs_bool(x); function bool : occurs_float(var bool : x) ::promise_total = true; /** @group optiontypes.float Return value of \a x (assumes that \a x is not absent) */ function var float : deopt(var opt float : x) ::promise_total = deopt_float(x); function var opt float: if_b_else_absent(var bool: b, var float: x) ::promise_total = let { var opt lb(x)..ub(x): y; constraint not occurs(y); } in if b then x else y endif; function var float: if_b_else_zero(var bool: b, var float: x) ::promise_total = if b then x else 0.0 endif; function var float : deopt_float(var float : x) ::promise_total = x; function var float : deopt_float(var opt float : x) ::promise_total = let { var bool : b = occurs_internal_float(x); var float : dx = deopt_internal_float(x); constraint (x = reverse_map_var_opt_float(b,dx)) :: is_reverse_map; } in dx; function var int : deopt_float(var opt int : x) ::promise_total = deopt_int(x); function var int : deopt_float(var int : x) ::promise_total = x; function var bool : deopt_float(var opt bool : x) ::promise_total = deopt_bool(x); function var bool : deopt_float(var bool : x) ::promise_total = x; function float : deopt_float(opt float : x) ::promise_total = deopt(x); function int : deopt_float(opt int : x) ::promise_total = deopt(x); function bool : deopt_float(opt bool : x) ::promise_total = deopt(x); /** @group optiontypes.float True iff \a x is absent */ function var bool: absent(var opt float: x) ::promise_total = not occurs(x); function var bool: occurs_internal_float(var opt float: x) ::promise_total = let { var bool : b; } in b; function var float : deopt_internal_float(var opt float : x) ::promise_total = let { var lb(x)..ub(x): y } in y; function var opt float: reverse_map_var_opt_float(var bool: occ, var float: d); % :NOTE: Must define in cpp? function opt float: reverse_map_var_opt_float(bool: occ, float: d) ::promise_total = if occ then d else <> endif; % :NOTE: does it apply to float? /* predicate var_dom(var opt float:x, set of float: s) = let { var float: dx = deopt(x); set of float: new_dom = dom(dx) intersect s; } in if new_dom = {} then absent(x) else dx in new_dom endif; predicate var_dom(array[$T] of var opt float: x, set of float: d) = let { array[int] of var opt float: xx = array1d(x) } in forall (i in index_set(xx)) (var_dom(xx[i],d)); */ predicate float_opt_eq(var opt float: x, var opt float: y) = deopt(x) = deopt(y) /\ occurs(x) = occurs(y); /** @group optiontypes.float Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is greater than the value of \a y. */ function var bool: '>'(var opt float: x, var opt float: y) = absent(x) \/ absent(y) \/ deopt(x) > deopt(y); /** @group optiontypes.float Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is greater than or equal to the value of \a y. */ function var bool: '>='(var opt float: x, var opt float: y) = absent(x) \/ absent(y) \/ deopt(x) >= deopt(y); /** @group optiontypes.float Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is less than the value of \a y. */ function var bool: '<'(var opt float: x, var opt float: y) = absent(x) \/ absent(y) \/ deopt(x) < deopt(y); /** @group optiontypes.float Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is less than or equal to the value of \a y. */ function var bool: '<='(var opt float: x, var opt float: y) = absent(x) \/ absent(y) \/ deopt(x) <= deopt(y); /** @group optiontypes.float Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is greater than the value of \a y. */ function bool: '>'(opt float: x, opt float: y) = absent(x) \/ absent(y) \/ deopt(x) > deopt(y); /** @group optiontypes.float Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is greater than or equal to the value of \a y. */ function bool: '>='(opt float: x, opt float: y) = absent(x) \/ absent(y) \/ deopt(x) >= deopt(y); /** @group optiontypes.float Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is less than the value of \a y. */ function bool: '<'(opt float: x, opt float: y) = absent(x) \/ absent(y) \/ deopt(x) < deopt(y); /** @group optiontypes.float Weak comparison: true iff either \a x or \a y is absent, or both occur and the value of \a x is less than or equal to the value of \a y. */ function bool: '<='(opt float: x, opt float: y) = absent(x) \/ absent(y) \/ deopt(x) <= deopt(y); /** @group optiontypes.float Return minimum of elements in \a x that are not absent, or absent if all elements in \a x are absent. */ % :NOTE: since -oo is always a lb for float variables, should we instead return -oo if all absent? function var opt float: min(array[int] of var opt float: x) ::promise_total = let { var opt lb_array(x)..ub_array(x): m; var lb_array(x)..ub_array(x): xmax; constraint if ub(xmax) != infinity then xmax = ub(xmax) else forall (i in index_set(x)) (xmax >= deopt(x[i])) endif; constraint occurs(m) <-> exists (i in index_set(x)) (occurs(x[i])); constraint occurs(m) -> deopt(m) = min([if occurs(xi) then deopt(xi) else xmax endif | xi in x]); } in m; /** @group optiontypes.float Return maximum of elements in \a x that are not absent, or absent if all elements in \a x are absent. */ function var opt float: max(array[int] of var opt float: x) ::promise_total = let { var opt lb_array(x)..ub_array(x): m; var lb_array(x)..ub_array(x): xmin; constraint if lb(xmin) != -infinity then xmin = lb(xmin) else forall (i in index_set(x)) (xmin <= deopt(x[i])) endif; constraint occurs(m) <-> exists (i in index_set(x)) (occurs(x[i])); constraint occurs(m) -> deopt(m) = max([if occurs(xi) then deopt(xi) else xmin endif | xi in x]); } in m; /** @group optiontypes.float Weak addition. Return sum of \a x and \a y if both are present, otherwise return absent. */ function var opt float: '~+'(var opt float: x, var opt float: y) ::promise_total = let { float: l = if lb(x)=-infinity \/ lb(y)=-infinity then -infinity else lb(x)+lb(y) endif; float: u = if ub(x)=infinity \/ ub(y)=infinity then infinity else ub(x)+ub(y) endif; var opt l..u: result; constraint absent(x) \/ absent(y) -> result = <>; constraint absent(x) \/ absent(y) \/ result = deopt(x)+deopt(y); } in result; /** @group optiontypes.float Weak subtraction. Return difference of \a x and \a y if both are present, otherwise return absent. */ function var opt float: '~-'(var opt float: x, var opt float: y) ::promise_total = let { float: l = if lb(x)=-infinity \/ ub(y)=infinity then -infinity else lb(x)-ub(y) endif; float: u = if ub(x)=infinity \/ lb(y)=-infinity then infinity else ub(x)-lb(y) endif; var opt l..u: result; constraint absent(x) \/ absent(y) -> result = <>; constraint absent(x) \/ absent(y) \/ result = deopt(x)-deopt(y); } in result; /** @group optiontypes.float Weak multiplication. Return product of \a x and \a y if both are present, otherwise return absent. */ function var opt float: '~*'(var opt float: x, var opt float: y) ::promise_total = if absent(x) \/ absent(y) then <> else deopt(x)*deopt(y) endif; /** @group optiontypes.float Weak equality. True if either \a x or \a y are absent, or present and equal.*/ function var bool: '~='(var opt float: x, var opt float: y) ::promise_total = absent(x) \/ absent(y) \/ deopt(x)=deopt(y); /** @group optiontypes.float Return optional 0/1 float that is absent iff \a x is absent, and 1 iff \a x occurs and is true. */ function var opt float: bool2float(var opt bool: x) ::promise_total = let { var opt 0.0..1.0: xi; constraint absent(xi)=absent(x); constraint deopt(xi)=bool2float(deopt(x)); } in xi; /** @group optiontypes.int Return optional 0/1 integer that is absent iff \a x is absent, and 1 iff \a x occurs and is true. */ function var opt float: int2float(var opt int: x) ::promise_total = let { var opt int2float(lb(x))..int2float(ub(x)): xi; constraint absent(xi)=absent(x); constraint deopt(xi)=int2float(deopt(x)); } in xi; /** @group optiontypes.float True iff both \a x and \a y are absent or both are present and have the same value. */ predicate float_eq(var opt float: x, var opt float: y) = (absent(x) /\ absent(y)) \/ (occurs(x) /\ occurs(y) /\ (deopt(x)=deopt(y))::maybe_partial); /** @group optiontypes.float True iff only one of \a x and \a y is absent or both are present and have different values. */ predicate float_ne(var opt float : x, var opt float : y) = (absent(x) != absent(y)) \/ (occurs(x) /\ occurs(y) /\ (deopt(x)!=deopt(y))::maybe_partial); /** @group optiontypes.float Optional addition. Return sum of \a x and \a y, with absent replaced by 0. */ function var float: '+'(var opt float: x, var opt float: y) ::promise_total = if occurs(x) then deopt(x) else 0 endif + if occurs(y) then deopt(y) else 0 endif; /** @group optiontypes.float Optional addition. Return sum of \a x and \a y, with absent replaced by 0. */ function float: '+'(opt float: x, opt float: y) ::promise_total = if occurs(x) then deopt(x) else 0 endif + if occurs(y) then deopt(y) else 0 endif; /** @group optiontypes.float Optional subtraction. Return difference of \a x and \a y, with absent replaced by 0. */ function var float: '-'(var opt float: x, var opt float: y) ::promise_total = if occurs(x) then deopt(x) else 0 endif - if occurs(y) then deopt(y) else 0 endif; /** @group optiontypes.float Optional subtraction. Return difference of \a x and \a y, with absent replaced by 0. */ function float: '-'(opt float: x, opt float: y) ::promise_total = if occurs(x) then deopt(x) else 0 endif - if occurs(y) then deopt(y) else 0 endif; /** @group optiontypes.float Optional multiplication. Return product of \a x and \a y, with absent replaced by 1. */ function var float: '*'(var opt float: x, var opt float: y) ::promise_total = if occurs(x) then deopt(x) else 1 endif * if occurs(y) then deopt(y) else 1 endif; /** @group optiontypes.float Optional multiplication. Return product of \a x and \a y, with absent replaced by 1. */ function float: '*'(opt float: x, opt float: y) ::promise_total = if occurs(x) then deopt(x) else 1 endif * if occurs(y) then deopt(y) else 1 endif; /** @group optiontypes.float Optional division. Return \a x div \a y, with absent replaced by 1. */ function var float: 'div'(var opt float: x, var opt float: y) ::promise_total = if occurs(x) then deopt(x) else 1 endif div if occurs(y) then deopt(y) else 1 endif; /** @group optiontypes.float Optional division. Return \a x div \a y, with absent replaced by 1. */ function float: 'div'(opt float: x, opt float: y) ::promise_total = if occurs(x) then deopt(x) else 1 endif div if occurs(y) then deopt(y) else 1 endif; /** @group optiontypes.float Optional modulo. Return \a x mod \a y, with absent replaced by 1. */ function var float: 'mod'(var opt float: x, var opt float: y) ::promise_total = if occurs(x) then deopt(x) else 1 endif mod if occurs(y) then deopt(y) else 1 endif; /** @group optiontypes.float Optional modulo. Return \a x mod \a y, with absent replaced by 1. */ function float: 'mod'(opt float: x, opt float: y) ::promise_total = if occurs(x) then deopt(x) else 1 endif mod if occurs(y) then deopt(y) else 1 endif; /** @group optiontypes.float Return sum of non-absent elements of \a x. */ function var float: sum(array[int] of var opt float: x) = sum (i in index_set(x)) (let { var float: dx = deopt(x[i]) } in if occurs(x[i]) then dx else 0 endif); /** @group optiontypes.float Return sum of non-absent elements of \a x. */ function float: sum(array[int] of opt float: x) = sum (i in index_set(x)) (if occurs(x[i]) then deopt(x[i]) else 0 endif); /** @group optiontypes.float Return product of non-absent elements of \a x. */ function var float: product(array[int] of var opt float: x) = product (i in index_set(x)) (let { var float: dx = deopt(x[i]) } in if occurs(x[i]) then dx else 1 endif); /** @group optiontypes.float Return product of non-absent elements of \a x. */ function float: product(array[int] of opt float: x) = product (i in index_set(x)) (if occurs(x[i]) then deopt(x[i]) else 1 endif); /** @group optiontypes.float Return absent if \a idx is absent, otherwise return \a x[\a idx] */ function var opt float: element(var opt int: idx, array[int] of var float: x) = if absent(idx) then <> else element(deopt(idx),x) endif; /** @group optiontypes.float Return absent if \a idx1 or \a idx2 is absent, otherwise return \a x[\a idx1, \a idx2] */ function var opt float: element(var opt int: idx1, var opt int: idx2, array[int,int] of var float: x) = if absent(idx1) \/ absent(idx2) then <> else element(deopt(idx1),deopt(idx2),x) endif; /** @group optiontypes.float Return \a x[\a idx] */ function var opt float: element(var int: idx, array[int] of var opt float: x) = let { var opt float: r; constraint occurs(r) = element(idx,array1d(index_set(x),[occurs(x[i]) | i in index_set(x)])); constraint deopt(r) = element(idx,array1d(index_set(x),[deopt(x[i]) | i in index_set(x)])); } in r; /** @group optiontypes.float Return \a x[\a idx1, \a idx2] */ function var opt float: element(var int: idx1, var int: idx2, array[int,int] of var opt float: x) = let { var opt float: r; constraint occurs(r) = element(idx1,idx2, array2d(index_set_1of2(x),index_set_2of2(x),[occurs(x[i,j]) | i in index_set_1of2(x), j in index_set_2of2(x)])); constraint deopt(r) = element(idx1,idx2, array2d(index_set_1of2(x),index_set_2of2(x),[deopt(x[i,j]) | i in index_set_1of2(x), j in index_set_2of2(x)])); } in r; /** @group optiontypes.float Return absent if \a idx is absent, otherwise return \a x[\a idx] */ function var opt float: element(var opt int: idx, array[int] of var opt float: x) = if absent(idx) then <> else element(deopt(idx),x) endif; /** @group optiontypes.float Return absent if \a idx1 or \a idx2 is absent, otherwise return \a x[\a idx1, \a idx2] */ function var opt float: element(var opt int: idx1, var opt int: idx2, array[int,int] of var opt float: x) = if absent(idx1) \/ absent(idx2) then <> else element(deopt(idx1),deopt(idx2),x) endif; /** @group optiontypes.float Search annotation for optional float variables */ annotation float_search(array[int] of var opt float: x, ann: a1, ann: a2, ann: a3) = float_search([if occurs(x[i]) then deopt(x[i]) else 0 endif | i in index_set(x)],a1,a2,a3); /** @group optiontypes.float Search annotation for optional float variables */ annotation float_search(array[int] of var opt float: x, ann: a1, ann: a2) = float_search([if occurs(x[i]) then deopt(x[i]) else 0 endif | i in index_set(x)],a1,a2); /* Internal function used to optimize over option type objective */ function var float: objective_deopt_(var opt float: x, bool: direction) = let { float: worst = if direction then lb(x)-1 else ub(x)+1 endif; } in if occurs(x) then deopt(x) else worst endif; /*** @groupdef options Compiler options */ /** @group options Whether to only generate domains that are contiguous ranges */ opt bool: mzn_opt_only_range_domains; /** @group options Check whether to only generate domains that are contiguous ranges */ test mzn_check_only_range_domains() = if absent(mzn_opt_only_range_domains) then false else deopt(mzn_opt_only_range_domains) endif; /** @group options If defined, this can be used to check that the MiniZinc compiler supports all the features used in the model. */ opt int: mzn_min_version_required; constraint assert(absent(mzn_min_version_required) \/ deopt(mzn_min_version_required) <= mzn_compiler_version(), "This model requires MiniZinc version "++mzn_version_to_string(deopt(mzn_min_version_required))++" but you are running version "++mzn_version_to_string(mzn_compiler_version())); predicate set_in(array[$T] of var int: X, set of int: s) = forall(x in array1d(X)) (x in s); predicate int_eq(array[$T] of var int: X, int: s) = forall(x in array1d(X)) (x = s); predicate float_eq(array[$T] of var int: X, float: s) = forall(x in array1d(X)) (x = s); predicate int_le(array[$T] of var int: X, int: s) = forall(x in array1d(X)) (x <= s); predicate int_le(int:s, array[$T] of var int: X) = forall(x in array1d(X)) (x >= s); predicate float_le(array[$T] of var float: X, float: s) = forall(x in array1d(X)) (x <= s); predicate float_le(float:s, array[$T] of var float: X) = forall(x in array1d(X)) (x >= s); include "builtins.mzn"; libminizinc-2.4.2/share/minizinc/std/steiner.mzn000066400000000000000000000057211360574160400217540ustar00rootroot00000000000000include "fzn_steiner.mzn"; include "fzn_steiner_reif.mzn"; include "fzn_dsteiner.mzn"; include "fzn_dsteiner_reif.mzn"; include "weighted_spanning_tree.mzn"; /** @group globals.graph Constrains the subgraph \a ns and \a es of a given directed graph to be a weighted spanning tree rooted at \a r of weight \a W. @param N: the number of nodes in the given graph @param E: the number of edges in the given graph @param from: the leaving node 1..\a N for each edge @param to: the entering node 1..\a N for each edge @param w: the weight of each edge @param r: the root node (which may be variable) @param ns: a Boolean for each node whether it is in the subgraph @param es: a Boolean for each edge whether it is in the subgraph @param K: the weight of the tree */ predicate dsteiner(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of int: w, var int: r, array[int] of var bool: ns, array[int] of var bool: es, var int: K) = assert(index_set(from) = 1..E,"dsteiner: index set of from must be 1..\(E)") /\ assert(index_set(to) = 1..E,"dsteiner: index set of to must be 1..\(E)") /\ assert(index_set(ns) = 1..N,"dsteiner: index set of ns must be 1..\(N)") /\ assert(index_set(es) = 1..E,"dsteiner: index set of es must be 1..\(E)") /\ assert(index_set(w) = 1..E,"dsteiner: index set of w must be 1..\(E)") /\ if forall(n in 1..N)(is_fixed(ns[n]) /\ fix(ns[n])) then d_weighted_spanning_tree(N,E,from,to,w,r,es,K) else fzn_dsteiner(N,E,from,to,w,r,ns,es,K) endif; /** @group globals.graph Constrains the set of edges \a es of a given undirected graph to be a weighted spanning tree of weight \a W. @param N: the number of nodes in the given graph @param E: the number of edges in the given graph @param from: the leaving node 1..\a N for each edge @param to: the entering node 1..\a N for each edge @param w: the weight of each edge @param ns: a Boolean for each node whether it is in the subgraph @param es: a Boolean for each edge whether it is in the subgraph @param K: the weight of the tree **/ predicate steiner(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of int: w, array[int] of var bool: ns, array[int] of var bool: es, var int: K) = assert(index_set(from) = 1..E,"steiner: index set of from must be 1..\(E)") /\ assert(index_set(to) = 1..E,"steiner: index set of to must be 1..\(E)") /\ assert(index_set(ns) = 1..N,"steiner: index set of ns must be 1..\(N)") /\ assert(index_set(es) = 1..E,"steiner: index set of es must be 1..\(E)") /\ assert(index_set(w) = 1..E,"steiner: index set of w must be 1..\(E)") /\ if forall(n in 1..N)(is_fixed(ns[n]) /\ fix(ns[n])) then weighted_spanning_tree(N,E,from,to,w,es,K) else fzn_steiner(N,E,from,to,w,ns,es,K) endif; %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/strict_lex2.mzn000066400000000000000000000005131360574160400225370ustar00rootroot00000000000000include "fzn_strict_lex2.mzn"; include "fzn_strict_lex2_reif.mzn"; /** @group globals.lexicographic Require adjacent rows and adjacent columns in the array \a x to be lexicographically ordered. Adjacent rows and adjacent columns cannot be equal. */ predicate strict_lex2(array[int, int] of var int: x) = fzn_strict_lex2(x); libminizinc-2.4.2/share/minizinc/std/strictly_decreasing.mzn000066400000000000000000000016541360574160400243450ustar00rootroot00000000000000include "fzn_strictly_decreasing_int.mzn"; include "fzn_strictly_decreasing_int_reif.mzn"; include "fzn_strictly_decreasing_bool.mzn"; include "fzn_strictly_decreasing_bool_reif.mzn"; include "analyse_all_different.mzn"; %-----------------------------------------------------------------------------% % Requires that the array 'x' is in strict decreasing order %-----------------------------------------------------------------------------% predicate strictly_decreasing(array[int] of var bool: x) = analyse_all_different(x) /\ fzn_strictly_decreasing_bool(x); predicate strictly_decreasing_reif(array[int] of var bool: x, var bool: b) = fzn_strictly_decreasing_bool_reif(x,b); predicate strictly_decreasing(array[int] of var int: x) = analyse_all_different(x) /\ fzn_strictly_decreasing_int(x); predicate strictly_decreasing_reif(array[int] of var int: x, var bool: b) = fzn_strictly_decreasing_int_reif(x,b); libminizinc-2.4.2/share/minizinc/std/strictly_increasing.mzn000066400000000000000000000016551360574160400243640ustar00rootroot00000000000000include "fzn_strictly_increasing_int.mzn"; include "fzn_strictly_increasing_int_reif.mzn"; include "fzn_strictly_increasing_bool.mzn"; include "fzn_strictly_increasing_bool_reif.mzn"; include "analyse_all_different.mzn"; %-----------------------------------------------------------------------------% % Requires that the array 'x' is in strict increasing order %-----------------------------------------------------------------------------% predicate strictly_increasing(array[int] of var bool: x) = analyse_all_different(x) /\ fzn_strictly_increasing_bool(x); predicate strictly_increasing_reif(array[int] of var bool: x, var bool: b) = fzn_strictly_increasing_bool_reif(x,b); predicate strictly_increasing(array[int] of var int: x) = analyse_all_different(x) /\ fzn_strictly_increasing_int(x); predicate strictly_increasing_reif(array[int] of var int: x, var bool: b) = fzn_strictly_increasing_int_reif(x,b); libminizinc-2.4.2/share/minizinc/std/subcircuit.mzn000066400000000000000000000010211360574160400224440ustar00rootroot00000000000000include "fzn_subcircuit.mzn"; include "fzn_subcircuit_reif.mzn"; /** @group globals Constrains the elements of \a x to define a subcircuit where \a x[\p i] = \p j means that \p j is the successor of \p i and \a x[\p i] = \p i means that \p i is not in the circuit. */ predicate subcircuit(array[int] of var int: x) = fzn_subcircuit(x); predicate subcircuit_reif(array[int] of var int: x, var bool: b) = fzn_subcircuit_reif(x, b); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/subgraph.mzn000066400000000000000000000041341360574160400221130ustar00rootroot00000000000000include "fzn_subgraph_int.mzn"; include "fzn_subgraph_int_reif.mzn"; include "fzn_subgraph_enum.mzn"; include "fzn_subgraph_enum_reif.mzn"; /** @group globals.graph Constrains that \a ns and \a es is a subgraph of a given directed graph. @param N: the number of nodes in the given graph @param E: the number of edges in the given graph @param from: the leaving node 1..\a N for each edge @param to: the entering node 1..\a N for each edge @param ns: a Boolean for each node whether it is in the subgraph @param es: a Boolean for each edge whether it is in the subgraph */ predicate subgraph(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of var bool: ns, array[int] of var bool: es) = assert(index_set(from) = 1..E,"subgraph: index set of from must be 1..\(E)") /\ assert(index_set(to) = 1..E,"subgraph: index set of to must be 1..\(E)") /\ assert(index_set(ns) = 1..N,"subgraph: index set of ns must be 1..\(N)") /\ assert(index_set(es) = 1..E,"subgraph: index set of es must be 1..\(E)") /\ fzn_subgraph(N,E,from,to,ns,es); /** @group globals.graph Constrains that \a ns and \a es is a subgraph of a given directed graph. @param from: the leaving node for each edge @param to: the entering node for each edge @param ns: a Boolean for each node whether it is in the subgraph @param es: a Boolean for each edge whether it is in the subgraph */ predicate subgraph(array[int] of $$N: from, array[int] of $$N: to, array[$$N] of var bool: ns, array[int] of var bool: es) = assert(index_set(from) = index_set(to),"subgraph: index set of from and to must be identical") /\ assert(index_set(from) = index_set(es),"subgraph: index set of from and es must be identical") /\ assert(dom_array(from) subset index_set(ns),"subgraph: elements in from must be in index set of ns") /\ assert(dom_array(to) subset index_set(ns),"subgraph: elements in to must be in index set of ns") /\ fzn_subgraph(from,to,ns,es); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/sum_pred.mzn000066400000000000000000000007361360574160400221220ustar00rootroot00000000000000include "fzn_sum_pred.mzn"; include "fzn_sum_pred_reif.mzn"; /** @group globals Requires that the sum of \a cs[\p i1]..\a cs[\p iN] equals \a s, where \p i1..\p iN are the elements of the \a i th set in \a sets. Nb: not called 'sum' as in the constraints catalog because 'sum' is a MiniZinc built-in function. */ predicate sum_pred(var int: i, array[int] of set of int: sets, array[int] of int: cs, var int: s) = fzn_sum_pred(i, sets, cs, s); libminizinc-2.4.2/share/minizinc/std/sum_set.mzn000066400000000000000000000005771360574160400217660ustar00rootroot00000000000000include "fzn_sum_set.mzn"; include "fzn_sum_set_reif.mzn"; /** @group globals Requires that the sum of the weights \a ws[\p i1]..\a ws[\p iN] equals \a s, where \a vs[\p i1]..\a vs[\p iN] are the elements appearing in set \a x */ predicate sum_set(array[int] of int: vs, array[int] of int: ws, var set of int: x, var int: s) = fzn_sum_set(vs, ws, x, s); libminizinc-2.4.2/share/minizinc/std/symmetric_all_different.mzn000066400000000000000000000010351360574160400251670ustar00rootroot00000000000000include "analyse_all_different.mzn"; include "fzn_symmetric_all_different.mzn"; include "fzn_symmetric_all_different_reif.mzn"; /** @group globals.alldifferent Requires the array of integers \a x to be all different, and for all \p i, \a x[\p i]=j \(\rightarrow\) \a x[\p j]=\p i. */ predicate symmetric_all_different(array[int] of var int:x) = analyse_all_different(x) /\ fzn_symmetric_all_different(x); predicate symmetric_all_different_reif(array[int] of var int:x, var bool: b) = fzn_symmetric_all_different_reif(x,b); libminizinc-2.4.2/share/minizinc/std/table.mzn000066400000000000000000000016101360574160400213630ustar00rootroot00000000000000include "table_bool.mzn"; include "table_int.mzn"; /** @group globals.extensional Represents the constraint \a x in \a t where we consider each row in \a t to be a tuple and \a t as a set of tuples. */ predicate table(array[int] of var bool: x, array[int, int] of bool: t) = assert (index_set_2of2(t) == index_set(x), "The second dimension of the table must equal the number of variables " ++ "in the first argument", table_bool(x, t) ); /** @group globals.extensional Represents the constraint \a x in \a t where we consider each row in \a t to be a tuple and \a t as a set of tuples. */ predicate table(array[int] of var int: x, array[int, int] of int: t) = assert (index_set_2of2(t) == index_set(x), "The second dimension of the table must equal the number of variables " ++ "in the first argument", table_int(x, t) ); libminizinc-2.4.2/share/minizinc/std/table_bool.mzn000066400000000000000000000012631360574160400224020ustar00rootroot00000000000000include "fzn_table_bool.mzn"; include "fzn_table_bool_reif.mzn"; %-----------------------------------------------------------------------------% % A table constraint: table(x, t) represents the constraint x in t where we % consider each row in t to be a tuple and t as a set of tuples. %-----------------------------------------------------------------------------% predicate table_bool(array[int] of var bool: x, array[int, int] of bool: t) = fzn_table_bool(x, t); predicate table_bool_reif(array[int] of var bool: x, array[int, int] of bool: t, var bool: b) = fzn_table_bool_reif(x, t, b); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/table_int.mzn000066400000000000000000000012721360574160400222410ustar00rootroot00000000000000include "fzn_table_int.mzn"; include "fzn_table_int_reif.mzn"; %-----------------------------------------------------------------------------% % A table constraint table(x, t) represents the constraint x in t where we % consider each row in t to be a tuple and t as a set of tuples. %-----------------------------------------------------------------------------% predicate table_int(array[int] of var int: x, array[int, int] of int: t) = fzn_table_int(x, t); predicate table_int_reif(array[int] of var int: x, array[int, int] of int: t, var bool: b) = fzn_table_int_reif(x, t, b); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/tree.mzn000066400000000000000000000105621360574160400212410ustar00rootroot00000000000000include "fzn_tree_int.mzn"; include "fzn_tree_int_reif.mzn"; include "fzn_tree_enum.mzn"; include "fzn_tree_enum_reif.mzn"; include "fzn_dtree_int.mzn"; include "fzn_dtree_int_reif.mzn"; include "fzn_dtree_enum.mzn"; include "fzn_dtree_enum_reif.mzn"; /** @group globals.graph Constrains the subgraph \a ns and \a es of a given directed graph to be a tree rooted at \a r. @param N: the number of nodes in the given graph @param E: the number of edges in the given graph @param from: the leaving node 1..\a N for each edge @param to: the entering node 1..\a N for each edge @param r: the root node (which may be variable) @param ns: a Boolean for each node whether it is in the subgraph @param es: a Boolean for each edge whether it is in the subgraph */ predicate dtree(int: N, int: E, array[int] of int: from, array[int] of int: to, var int: r, array[int] of var bool: ns, array[int] of var bool: es) = assert(index_set(from) = 1..E,"dtree: index set of from must be 1..\(E)") /\ assert(index_set(to) = 1..E,"dtree: index set of to must be 1..\(E)") /\ assert(index_set(ns) = 1..N,"dtree: index set of ns must be 1..\(N)") /\ assert(index_set(es) = 1..E,"dtree: index set of es must be 1..\(E)") /\ fzn_dtree(N,E,from,to,r,ns,es); /** @group globals.graph Constrains the subgraph \a ns and \a es of a given directed graph to be at tree rooted at \a r. @param from: the leaving node for each edge @param to: the entering node for each edge @param r: the root node (which may be variable) @param ns: a Boolean for each node whether it is in the subgraph @param es: a Boolean for each edge whether it is in the subgraph */ predicate dtree(array[int] of $$N: from, array[int] of $$N: to, var $$N: r, array[$$N] of var bool: ns, array[int] of var bool: es) = assert(index_set(from) = index_set(to),"dreachable: index set of from and to must be identical") /\ assert(index_set(from) = index_set(es),"dreachable: index set of from and es must be identical") /\ assert(dom_array(from) subset index_set(ns),"dreachable: nodes in from must be in index set of ns") /\ assert(dom_array(from) subset index_set(ns),"dreachable: nodes in to must be in index set of ns") /\ fzn_dtree(from,to,r,ns,es); %-----------------------------------------------------------------------------% /** @group globals.graph Constrains the subgraph \a ns and \a es of a given undirected graph to be a tree rooted at \a r. @param N: the number of nodes in the given graph @param E: the number of edges in the given graph @param from: the leaving node 1..\a N for each edge @param to: the entering node 1..\a N for each edge @param r: the root node (which may be variable) @param ns: a Boolean for each node whether it is in the subgraph @param es: a Boolean for each edge whether it is in the subgraph */ predicate tree(int: N, int: E, array[int] of int: from, array[int] of int: to, var int: r, array[int] of var bool: ns, array[int] of var bool: es) = assert(index_set(from) = 1..E,"tree: index set of from must be 1..\(E)") /\ assert(index_set(to) = 1..E,"tree: index set of to must be 1..\(E)") /\ assert(index_set(ns) = 1..N,"tree: index set of ns must be 1..\(N)") /\ assert(index_set(es) = 1..E,"tree: index set of es must be 1..\(E)") /\ fzn_tree(N,E,from,to,r,ns,es); /** @group globals.graph Constrains the subgraph \a ns and \a es of a given undirected graph to be at tree rooted at \a r. @param from: the leaving node for each edge @param to: the entering node for each edge @param r: the root node (which may be variable) @param ns: a Boolean for each node whether it is in the subgraph @param es: a Boolean for each edge whether it is in the subgraph */ predicate tree(array[int] of $$N: from, array[int] of $$N: to, var $$N: r, array[$$N] of var bool: ns, array[int] of var bool: es) = assert(index_set(from) = index_set(to),"dreachable: index set of from and to must be identical") /\ assert(index_set(from) = index_set(es),"dreachable: index set of from and es must be identical") /\ assert(dom_array(from) subset index_set(ns),"dreachable: nodes in from must be in index set of ns") /\ assert(dom_array(from) subset index_set(ns),"dreachable: nodes in to must be in index set of ns") /\ fzn_tree(from,to,r,ns,es); libminizinc-2.4.2/share/minizinc/std/value_precede.mzn000066400000000000000000000013511360574160400231010ustar00rootroot00000000000000include "value_precede_int.mzn"; include "value_precede_set.mzn"; /** @group globals.lexicographic Requires that \a s precede \a t in the array \a x. Precedence means that if any element of \a x is equal to \a t, then another element of \a x with a lower index is equal to \a s. */ predicate value_precede(int: s, int: t, array[int] of var int: x) = value_precede_int(s, t, x); /** @group globals.lexicographic Requires that \a s precede \a t in the array \a x. Precedence means that if an element of \a x contains \a t but not \a s, then another element of \a x with lower index contains \a s but not \a t. */ predicate value_precede(int: s, int: t, array[int] of var set of int: x) = value_precede_set(s, t, x); libminizinc-2.4.2/share/minizinc/std/value_precede_chain.mzn000066400000000000000000000015401360574160400242430ustar00rootroot00000000000000include "value_precede_chain_int.mzn"; include "value_precede_chain_set.mzn"; /** @group globals.lexicographic Requires that \a c[\p i] precedes \a c[\p i +1] in the array \a x. Precedence means that if any element of \a x is equal to \a c[\p i +1], then another element of \a x with a lower index is equal to \a c[\p i]. */ predicate value_precede_chain(array[int] of int: c, array[int] of var int: x) = value_precede_chain_int(c, x); /** @group globals.lexicographic Requires that \a c[\p i] precedes \a c[\p i +1] in the array \a x. Precedence means that if an element of \a x contains \a c[\p i +1] but not \a c[\p i], then another element of \a x with lower index contains \a c[\p i] but not \a c[\p i +1]. */ predicate value_precede_chain(array[int] of int: c, array[int] of var set of int: x) = value_precede_chain_set(c, x); libminizinc-2.4.2/share/minizinc/std/value_precede_chain_int.mzn000066400000000000000000000003271360574160400251170ustar00rootroot00000000000000include "fzn_value_precede_chain_int.mzn"; include "fzn_value_precede_chain_int_reif.mzn"; predicate value_precede_chain_int(array[int] of int: c, array[int] of var int: x) = fzn_value_precede_chain_int(c, x); libminizinc-2.4.2/share/minizinc/std/value_precede_chain_set.mzn000066400000000000000000000003361360574160400251200ustar00rootroot00000000000000include "fzn_value_precede_chain_set.mzn"; include "fzn_value_precede_chain_set_reif.mzn"; predicate value_precede_chain_set(array[int] of int: c, array[int] of var set of int: x) = fzn_value_precede_chain_set(c, x); libminizinc-2.4.2/share/minizinc/std/value_precede_int.mzn000066400000000000000000000002731360574160400237550ustar00rootroot00000000000000include "fzn_value_precede_int.mzn"; include "fzn_value_precede_int_reif.mzn"; predicate value_precede_int(int: s, int: t, array[int] of var int: x) = fzn_value_precede_int(s, t, x);libminizinc-2.4.2/share/minizinc/std/value_precede_set.mzn000066400000000000000000000003031360574160400237500ustar00rootroot00000000000000include "fzn_value_precede_set.mzn"; include "fzn_value_precede_set_reif.mzn"; predicate value_precede_set(int: s, int: t, array[int] of var set of int: x) = fzn_value_precede_set(s, t, x); libminizinc-2.4.2/share/minizinc/std/weighted_spanning_tree.mzn000066400000000000000000000044121360574160400250130ustar00rootroot00000000000000include "fzn_wst.mzn"; include "fzn_wst_reif.mzn"; include "fzn_dwst.mzn"; include "fzn_dwst_reif.mzn"; /** @group globals.graph Constrains the set of edges \a es of a given directed graph to be a weighted spanning tree rooted at \a r of weight \a W. @param N: the number of nodes in the given graph @param E: the number of edges in the given graph @param from: the leaving node 1..\a N for each edge @param to: the entering node 1..\a N for each edge @param w: the weight of each edge @param r: the root node (which may be variable) @param es: a Boolean for each edge whether it is in the subgraph @param K: the weight of the tree */ predicate d_weighted_spanning_tree(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of int: w, var int: r, array[int] of var bool: es, var int: K) = assert(index_set(from) = 1..E,"dwst: index set of from must be 1..\(E)") /\ assert(index_set(to) = 1..E,"dwst: index set of to must be 1..\(E)") /\ assert(index_set(es) = 1..E,"dwst: index set of es must be 1..\(E)") /\ assert(index_set(w) = 1..E,"dwst: index set of w must be 1..\(E)") /\ fzn_dwst(N,E,from,to,w,r,es,K); /** @group globals.graph Constrains the set of edges \a es of a given undirected graph to be a weighted spanning tree of weight \a W. @param N: the number of nodes in the given graph @param E: the number of edges in the given graph @param from: the leaving node 1..\a N for each edge @param to: the entering node 1..\a N for each edge @param w: the weight of each edge @param es: a Boolean for each edge whether it is in the subgraph @param K: the weight of the tree **/ predicate weighted_spanning_tree(int: N, int: E, array[int] of int: from, array[int] of int: to, array[int] of int: w, array[int] of var bool: es, var int: K) = assert(index_set(from) = 1..E,"wst: index set of from must be 1..\(E)") /\ assert(index_set(to) = 1..E,"wst: index set of to must be 1..\(E)") /\ assert(index_set(es) = 1..E,"wst: index set of es must be 1..\(E)") /\ assert(index_set(w) = 1..E,"dwst: index set of w must be 1..\(E)") /\ fzn_wst(N,E,from,to,w,es,K); %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/write.mzn000066400000000000000000000015051360574160400214310ustar00rootroot00000000000000include "fzn_write.mzn"; include "fzn_write_reif.mzn"; /** @group globals.array Creates a new array \a O from an input array \a I with a change at position \a i to take value \a v \a I is an array of integers \a O is an array of integers with same index set as \a I \a i is an index for \a I \a v is an integer value */ predicate write(array[int] of var int: I, var int: i, var int: v, array[int] of var int: O) = assert(index_set(O) = index_set(I),"writet: index set of I must be same as O") /\ fzn_write(I, i, v, O); function array[int] of var int: write(array[int] of var int: I, var int: i, var int: v) = let { array[index_set(I)] of var int: O; constraint fzn_write(I,i,v,O); } in O; %-----------------------------------------------------------------------------% libminizinc-2.4.2/share/minizinc/std/writes.mzn000066400000000000000000000022401360574160400216110ustar00rootroot00000000000000include "fzn_writes.mzn"; include "fzn_writes_reif.mzn"; /** @group globals.array Creates a new array \a O from an input array \a I with a simultaneous change at positions \a P to values \a V \a I is an array of integers \a O is an array of integers with same index set as \a I \a P is an array of index values in \a I \a V is an array of integer values */ predicate writes(array[int] of var int: I, array[int] of var int: P, array[int] of var int: V, array[int] of var int: O) = assert(index_set(O) = index_set(I),"writes: index set of I must be same as O") /\ assert(index_set(P) = index_set(V),"writes: index set of P must be same as V") /\ fzn_writes(I, P, V, O); function array[int] of var int: writes(array[int] of var int: I, array[int] of var int: P, array[int] of var int: V) = assert(index_set(P) = index_set(V),"writes: index set of P must be same as V") /\ let { array[index_set(I)] of var int: O; constraint fzn_writes(I,P,V,O); } in O; %-----------------------------------------------------------------------------%libminizinc-2.4.2/share/minizinc/std/writes_seq.mzn000066400000000000000000000022511360574160400224630ustar00rootroot00000000000000include "fzn_writes_seq.mzn"; include "fzn_writes_seq_reif.mzn"; /** @group globals.array Creates a new array \a O from an input array \a I with a sequence of changes at positions \a P to take values \a V \a I is an array of integers \a O is an array of integers with same index set as \a I \a P is an array of index values in \a I \a V is an array of integer values */ predicate writes_seq(array[int] of var int: I, array[int] of var int: P, array[int] of var int: V, array[int] of var int: O) = assert(index_set(O) = index_set(I),"writes: index set of I must be same as O") /\ assert(index_set(P) = index_set(V),"writes: index set of P must be same as V") /\ fzn_writes_seq(I, P, V, O); function array[int] of var int: writes_seq(array[int] of var int: I, array[int] of var int: P, array[int] of var int: V) = let { array[index_set(I)] of var int: O; constraint assert(index_set(P) = index_set(V),"writes: index set of P must be same as V"); constraint fzn_writes_seq(I,P,V,O); } in O; %-----------------------------------------------------------------------------% libminizinc-2.4.2/solvers/000077500000000000000000000000001360574160400155315ustar00rootroot00000000000000libminizinc-2.4.2/solvers/MIP/000077500000000000000000000000001360574160400161565ustar00rootroot00000000000000libminizinc-2.4.2/solvers/MIP/MIP_cplex_solverfactory.cpp000066400000000000000000000006441360574160400234700ustar00rootroot00000000000000#include #include #include namespace MiniZinc { namespace { void getWrapper() { static MIP_SolverFactory _cplex_solver_factory; return; } } Cplex_SolverFactoryInitialiser::Cplex_SolverFactoryInitialiser(void) { getWrapper(); } } libminizinc-2.4.2/solvers/MIP/MIP_cplex_wrap.cpp000066400000000000000000001203001360574160400215270ustar00rootroot00000000000000// * -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #include #include #include #include #include #include #include #include #ifdef CPLEX_PLUGIN #ifdef HAS_DLFCN_H #include #elif defined HAS_WINDOWS_H #include #endif #endif using namespace std; #include #ifdef CPLEX_PLUGIN namespace { void* dll_open(const std::string& file) { #ifdef HAS_DLFCN_H if (MiniZinc::FileUtils::is_absolute(file)) { return dlopen( file.c_str(), RTLD_NOW); } if (void* so = dlopen( ("lib"+file+".so").c_str(), RTLD_NOW)) { return so; } return dlopen( ("lib"+file+".jnilib").c_str(), RTLD_NOW); #else if (MiniZinc::FileUtils::is_absolute(file)) { return LoadLibrary(file.c_str()); } else { return LoadLibrary((file+".dll").c_str()); } #endif } void* dll_sym(void* dll, const char* sym) { #ifdef HAS_DLFCN_H void* ret = dlsym(dll, sym); #else void* ret = GetProcAddress((HMODULE)dll, sym); #endif if (ret==NULL) throw MiniZinc::InternalError("cannot load symbol "+string(sym)+" from CPLEX dll"); return ret; } void dll_close(void* dll) { #ifdef HAS_DLFCN_H dlclose(dll); #else FreeLibrary((HMODULE)dll); #endif } } #endif const vector& CPLEXDLLs(void) { static const vector sCPLEXDLLs = { "cplex1290", "cplex1280", "cplex1270" }; return sCPLEXDLLs; } void MIP_cplex_wrapper::checkDLL() { #ifdef CPLEX_PLUGIN _cplex_dll = NULL; if ( options->sCPLEXDLL.size() ) { _cplex_dll = dll_open( options->sCPLEXDLL.c_str() ); } else { for( const auto& s: CPLEXDLLs() ) { _cplex_dll = dll_open( s.c_str() ); if ( NULL!=_cplex_dll ) { break; } } } if (_cplex_dll==NULL) { if (options->sCPLEXDLL.empty()) { throw MiniZinc::InternalError("cannot load cplex dll, specify --cplex-dll"); } else { throw MiniZinc::InternalError("cannot load cplex dll `"+options->sCPLEXDLL+"'"); } } *(void**)(&dll_CPXaddfuncdest) = dll_sym(_cplex_dll, "CPXaddfuncdest"); *(void**)(&dll_CPXaddindconstr) = dll_sym(_cplex_dll, "CPXaddindconstr"); *(void**)(&dll_CPXaddlazyconstraints) = dll_sym(_cplex_dll, "CPXaddlazyconstraints"); *(void**)(&dll_CPXaddmipstarts) = dll_sym(_cplex_dll, "CPXaddmipstarts"); *(void**)(&dll_CPXaddrows) = dll_sym(_cplex_dll, "CPXaddrows"); *(void**)(&dll_CPXaddusercuts) = dll_sym(_cplex_dll, "CPXaddusercuts"); *(void**)(&dll_CPXchgbds) = dll_sym(_cplex_dll, "CPXchgbds"); *(void**)(&dll_CPXchgmipstarts) = dll_sym(_cplex_dll, "CPXchgmipstarts"); *(void**)(&dll_CPXchgobjsen) = dll_sym(_cplex_dll, "CPXchgobjsen"); *(void**)(&dll_CPXcloseCPLEX) = dll_sym(_cplex_dll, "CPXcloseCPLEX"); *(void**)(&dll_CPXcreateprob) = dll_sym(_cplex_dll, "CPXcreateprob"); *(void**)(&dll_CPXcutcallbackadd) = dll_sym(_cplex_dll, "CPXcutcallbackadd"); *(void**)(&dll_CPXfreeprob) = dll_sym(_cplex_dll, "CPXfreeprob"); *(void**)(&dll_CPXgetbestobjval) = dll_sym(_cplex_dll, "CPXgetbestobjval"); *(void**)(&dll_CPXgetcallbackincumbent) = dll_sym(_cplex_dll, "CPXgetcallbackincumbent"); *(void**)(&dll_CPXgetcallbackinfo) = dll_sym(_cplex_dll, "CPXgetcallbackinfo"); *(void**)(&dll_CPXgetcallbacknodeinfo) = dll_sym(_cplex_dll, "CPXgetcallbacknodeinfo"); *(void**)(&dll_CPXgetcallbacknodex) = dll_sym(_cplex_dll, "CPXgetcallbacknodex"); *(void**)(&dll_CPXgetchannels) = dll_sym(_cplex_dll, "CPXgetchannels"); *(void**)(&dll_CPXgetdettime) = dll_sym(_cplex_dll, "CPXgetdettime"); *(void**)(&dll_CPXgeterrorstring) = dll_sym(_cplex_dll, "CPXgeterrorstring"); *(void**)(&dll_CPXgetmipstartindex) = dll_sym(_cplex_dll, "CPXgetmipstartindex"); *(void**)(&dll_CPXgetnodecnt) = dll_sym(_cplex_dll, "CPXgetnodecnt"); *(void**)(&dll_CPXgetnodeleftcnt) = dll_sym(_cplex_dll, "CPXgetnodeleftcnt"); *(void**)(&dll_CPXgetnumcols) = dll_sym(_cplex_dll, "CPXgetnumcols"); *(void**)(&dll_CPXgetnumrows) = dll_sym(_cplex_dll, "CPXgetnumrows"); *(void**)(&dll_CPXgetobjsen) = dll_sym(_cplex_dll, "CPXgetobjsen"); *(void**)(&dll_CPXgetobjval) = dll_sym(_cplex_dll, "CPXgetobjval"); *(void**)(&dll_CPXgetsolnpoolnumsolns) = dll_sym(_cplex_dll, "CPXgetsolnpoolnumsolns"); *(void**)(&dll_CPXgetstat) = dll_sym(_cplex_dll, "CPXgetstat"); *(void**)(&dll_CPXgetstatstring) = dll_sym(_cplex_dll, "CPXgetstatstring"); *(void**)(&dll_CPXgettime) = dll_sym(_cplex_dll, "CPXgettime"); *(void**)(&dll_CPXgetx) = dll_sym(_cplex_dll, "CPXgetx"); *(void**)(&dll_CPXmipopt) = dll_sym(_cplex_dll, "CPXmipopt"); *(void**)(&dll_CPXnewcols) = dll_sym(_cplex_dll, "CPXnewcols"); *(void**)(&dll_CPXopenCPLEX) = dll_sym(_cplex_dll, "CPXopenCPLEX"); *(void**)(&dll_CPXreadcopyparam) = dll_sym(_cplex_dll, "CPXreadcopyparam"); *(void**)(&dll_CPXsetdblparam) = dll_sym(_cplex_dll, "CPXsetdblparam"); *(void**)(&dll_CPXsetinfocallbackfunc) = dll_sym(_cplex_dll, "CPXsetinfocallbackfunc"); *(void**)(&dll_CPXsetintparam) = dll_sym(_cplex_dll, "CPXsetintparam"); *(void**)(&dll_CPXsetstrparam) = dll_sym(_cplex_dll, "CPXsetstrparam"); *(void**)(&dll_CPXsetlazyconstraintcallbackfunc) = dll_sym(_cplex_dll, "CPXsetlazyconstraintcallbackfunc"); *(void**)(&dll_CPXsetusercutcallbackfunc) = dll_sym(_cplex_dll, "CPXsetusercutcallbackfunc"); *(void**)(&dll_CPXversion) = dll_sym(_cplex_dll, "CPXversion"); *(void**)(&dll_CPXwriteparam) = dll_sym(_cplex_dll, "CPXwriteparam"); *(void**)(&dll_CPXwriteprob) = dll_sym(_cplex_dll, "CPXwriteprob"); #else dll_CPXaddfuncdest = CPXaddfuncdest; dll_CPXaddindconstr = CPXaddindconstr; dll_CPXaddlazyconstraints = CPXaddlazyconstraints; dll_CPXaddmipstarts = CPXaddmipstarts; dll_CPXaddrows = CPXaddrows; dll_CPXaddusercuts = CPXaddusercuts; dll_CPXchgbds = CPXchgbds; dll_CPXchgmipstarts = CPXchgmipstarts; dll_CPXchgobjsen = CPXchgobjsen; dll_CPXcloseCPLEX = CPXcloseCPLEX; dll_CPXcreateprob = CPXcreateprob; dll_CPXcutcallbackadd = CPXcutcallbackadd; dll_CPXfreeprob = CPXfreeprob; dll_CPXgetbestobjval = CPXgetbestobjval; dll_CPXgetcallbackincumbent = CPXgetcallbackincumbent; dll_CPXgetcallbackinfo = CPXgetcallbackinfo; dll_CPXgetcallbacknodeinfo = CPXgetcallbacknodeinfo; dll_CPXgetcallbacknodex = CPXgetcallbacknodex; dll_CPXgetchannels = CPXgetchannels; dll_CPXgetdettime = CPXgetdettime; dll_CPXgeterrorstring = CPXgeterrorstring; dll_CPXgetmipstartindex = CPXgetmipstartindex; dll_CPXgetnodecnt = CPXgetnodecnt; dll_CPXgetnodeleftcnt = CPXgetnodeleftcnt; dll_CPXgetnumcols = CPXgetnumcols; dll_CPXgetnumrows = CPXgetnumrows; dll_CPXgetobjsen = CPXgetobjsen; dll_CPXgetobjval = CPXgetobjval; dll_CPXgetsolnpoolnumsolns = CPXgetsolnpoolnumsolns; dll_CPXgetstat = CPXgetstat; dll_CPXgetstatstring = CPXgetstatstring; dll_CPXgettime = CPXgettime; dll_CPXgetx = CPXgetx; dll_CPXmipopt = CPXmipopt; dll_CPXnewcols = CPXnewcols; dll_CPXopenCPLEX = CPXopenCPLEX; dll_CPXreadcopyparam = CPXreadcopyparam; dll_CPXsetdblparam = CPXsetdblparam; dll_CPXsetinfocallbackfunc = CPXsetinfocallbackfunc; dll_CPXsetintparam = CPXsetintparam; dll_CPXsetstrparam = CPXsetstrparam; dll_CPXsetlazyconstraintcallbackfunc = CPXsetlazyconstraintcallbackfunc; dll_CPXsetusercutcallbackfunc = CPXsetusercutcallbackfunc; dll_CPXversion = CPXversion; dll_CPXwriteparam = CPXwriteparam; dll_CPXwriteprob = CPXwriteprob; #endif } string MIP_cplex_wrapper::getDescription(MiniZinc::SolverInstanceBase::Options* opt) { string v = "MIP wrapper for IBM ILOG CPLEX "; int status; Options def_options; Options* options = opt ? static_cast(opt) : &def_options; try { MIP_cplex_wrapper mcw(options); CPXENVptr env = mcw.dll_CPXopenCPLEX (&status); if (env) { v += mcw.dll_CPXversion (env); status = mcw.dll_CPXcloseCPLEX (&env); } else v += "[?? ...cannot open CPLEX env to query version]"; } catch (MiniZinc::InternalError&) { v += "[?? ...cannot open CPLEX env to query version]"; } v += " Compiled " __DATE__ " " __TIME__; return v; } string MIP_cplex_wrapper::getVersion(MiniZinc::SolverInstanceBase::Options* opt) { string v; int status; Options def_options; Options* options = opt ? static_cast(opt) : &def_options; try { MIP_cplex_wrapper mcw(options); CPXENVptr env = mcw.dll_CPXopenCPLEX (&status); if (env) { v += mcw.dll_CPXversion (env); status = mcw.dll_CPXcloseCPLEX (&env); } else { v += ""; } } catch (MiniZinc::InternalError&) { v += ""; } return v; } std::string MIP_cplex_wrapper::needDllFlag(void) { int status; Options options; try { MIP_cplex_wrapper mcw(&options); CPXENVptr env = mcw.dll_CPXopenCPLEX (&status); if (env) { return ""; } } catch (MiniZinc::InternalError&) { } return "--cplex-dll"; } string MIP_cplex_wrapper::getId() { return "cplex"; } string MIP_cplex_wrapper::getName() { return "CPLEX"; } vector MIP_cplex_wrapper::getTags() { return {"mip","float","api"}; } vector MIP_cplex_wrapper::getStdFlags() { return {"-a", "-n", "-p", "-s", "-v"}; } void MIP_cplex_wrapper::Options::printHelp(ostream& os) { os << "IBM ILOG CPLEX MIP wrapper options:" << std::endl // -s print statistics // << " --readParam read CPLEX parameters from file // << "--writeParam write CPLEX parameters to file // << "--tuneParam instruct CPLEX to tune parameters instead of solving << " --mipfocus \n 1: feasibility, 2: optimality, 3: move bound (default is 0, balanced)" << std::endl << " -a\n print intermediate solutions (use for optimization problems only TODO)" << std::endl << " -p \n use N threads, default: 1" << std::endl // << " --nomippresolve disable MIP presolving NOT IMPL" << std::endl << " --solver-time-limit \n stop search after N milliseconds wall time" << std::endl << " -n , --num-solutions \n" " stop search after N solutions" << std::endl << " -r , --random-seed \n" " random seed, integer" << std::endl << " --workmem , --nodefilestart \n" " maximal RAM for working memory used before writing to node file, GB, default: 0.5" << std::endl << " --nodefiledir \n" " nodefile directory" << std::endl << " --writeModel \n write model to (.lp, .mps, .sav, ...)" << std::endl << " --readParam \n read CPLEX parameters from file" << std::endl << " --writeParam \n write CPLEX parameters to file" << std::endl // << " --tuneParam instruct CPLEX to tune parameters instead of solving NOT IMPL" << " --absGap \n absolute gap |primal-dual| to stop" << std::endl << " --relGap \n relative gap |primal-dual|/ to stop. Default 1e-8, set <0 to use backend's default" << std::endl << " --intTol \n integrality tolerance for a variable. Default 1e-8" << std::endl << "\n --cplex-dll or \n CPLEX DLL, or base name, such as cplex1280, when using plugin. Default range tried: " << CPLEXDLLs().front() << " .. " << CPLEXDLLs().back() << std::endl // << " --objDiff objective function discretization. Default 1.0" << std::endl << std::endl; } bool MIP_cplex_wrapper::Options::processOption(int& i, std::vector& argv) { MiniZinc::CLOParser cop( i, argv ); if ( string(argv[i])=="-a" || string(argv[i])=="--all" || string(argv[i])=="--all-solutions" ) { flag_all_solutions = true; } else if (string(argv[i])=="-f") { // std::cerr << " Flag -f: ignoring fixed strategy anyway." << std::endl; } else if ( cop.get( "--mipfocus --mipFocus --MIPFocus --MIPfocus", &nMIPFocus ) ) { } else if ( cop.get( "--writeModel", &sExportModel ) ) { } else if ( cop.get( "-p", &nThreads ) ) { } else if ( cop.get( "--solver-time-limit", &nTimeout ) ) { } else if ( cop.get( "-n --num-solutions", &nSolLimit ) ) { } else if ( cop.get( "-r --random-seed", &nSeed ) ) { } else if ( cop.get( "--workmem --nodefilestart", &nWorkMemLimit ) ) { } else if ( cop.get( "--nodefiledir --NodefileDir", &sNodefileDir ) ) { } else if ( cop.get( "--readParam", &sReadParams ) ) { } else if ( cop.get( "--writeParam", &sWriteParams ) ) { } else if ( cop.get( "--absGap", &absGap ) ) { } else if ( cop.get( "--relGap", &relGap ) ) { } else if ( cop.get( "--intTol", &intTol ) ) { } else if ( cop.get( "--cplex-dll", &sCPLEXDLL ) ) { // } else if ( cop.get( "--objDiff", &objDiff ) ) { } else return false; return true; } void MIP_cplex_wrapper::wrap_assert(bool cond, string msg, bool fTerm) { if ( !cond ) { strcpy(cplex_buffer, "[NO ERROR STRING GIVEN]"); dll_CPXgeterrorstring (env, status, cplex_buffer); string msgAll = (" MIP_cplex_wrapper runtime error: " + msg + " " + cplex_buffer); cerr << msgAll << endl; if (fTerm) { cerr << "TERMINATING." << endl; throw runtime_error(msgAll); } } } void MIP_cplex_wrapper::openCPLEX() { checkDLL(); cbui.wrapper = this; /// Cleanup first. // cleanup(); /* Initialize the CPLEX environment */ env = dll_CPXopenCPLEX (&status); /* If an error occurs, the status value indicates the reason for failure. A call to CPXgeterrorstring will produce the text of the error message. Note that CPXopenCPLEX produces no output, so the only way to see the cause of the error is to use CPXgeterrorstring. For other CPLEX routines, the errors will be seen if the CPXPARAM_ScreenOutput indicator is set to CPX_ON. */ wrap_assert ( env, "Could not open CPLEX environment." ); /* Create the problem. */ lp = dll_CPXcreateprob (env, &status, "MIP_cplex_wrapper"); /* A returned pointer of NULL may mean that not enough memory was available or there was some other problem. In the case of failure, an error message will have been written to the error channel from inside CPLEX. In this example, the setting of the parameter CPXPARAM_ScreenOutput causes the error message to appear on stdout. */ wrap_assert ( lp, "Failed to create LP." ); } void MIP_cplex_wrapper::closeCPLEX() { /// Freeing the problem can be slow both in C and C++, see IBM forums. Skipping. /* Free up the problem as allocated by CPXcreateprob, if necessary */ // if ( lp != NULL ) { // status = CPXfreeprob (env, &lp); // cplex_wrap_assert ( !status, "CPXfreeprob failed." ); // } lp = 0; /* Free up the CPLEX environment, if necessary */ if ( env != NULL ) { status = dll_CPXcloseCPLEX (&env); wrap_assert ( !status, "Could not close CPLEX environment." ); } /// and at last: // MIP_wrapper::cleanup(); #ifdef CPLEX_PLUGIN // dll_close(cplex_dll); #endif } void MIP_cplex_wrapper::doAddVars (size_t n, double* obj, double* lb, double* ub, MIP_wrapper::VarType* vt, string *names) { /// Convert var types: vector ctype(n); vector pcNames(n); for (size_t i=0; i=bVal, "mzn-cplex: addIndicatorConstraint: bVal not 0/1" ); char ssense=getCPLEXConstrSense(sense); status = dll_CPXaddindconstr (env, lp, iBVar, 1-bVal, nnz, rhs, ssense, rmatind, rmatval, rowName.c_str()); wrap_assert( !status, "Failed to add indicator constraint." ); } bool MIP_cplex_wrapper::addWarmStart( const std::vector& vars, const std::vector vals ) { assert( vars.size()==vals.size() ); const char* sMSName = "MZNMS"; int msindex=-1; const int beg=0; /// Check if we already added a start status = dll_CPXgetmipstartindex (env, lp, sMSName, &msindex); if ( status ) { // not existent // status = dll_CPXaddmipstarts (env, lp, mcnt, nzcnt, beg, varindices, // values, effortlevel, mipstartname); status = dll_CPXaddmipstarts (env, lp, 1, vars.size(), &beg, vars.data(), vals.data(), nullptr, (char**)&sMSName); wrap_assert( !status, "Failed to add warm start." ); } else { // status = dll_CPXchgmipstarts (env, lp, mcnt, mipstartindices, nzcnt, beg, varindices, values, effortlevel); status = dll_CPXchgmipstarts (env, lp, 1, &msindex, vars.size(), &beg, vars.data(), vals.data(), nullptr); wrap_assert( !status, "Failed to extend warm start." ); } return true; } void MIP_cplex_wrapper::setVarBounds(int iVar, double lb, double ub) { wrap_assert( lb<=ub, "mzn-cplex: setVarBounds: lb>ub" ); char cl = 'L', cu = 'U'; status = dll_CPXchgbds (env, lp, 1, &iVar, &cl, &lb); wrap_assert( !status, "Failed to set lower bound." ); status = dll_CPXchgbds (env, lp, 1, &iVar, &cu, &ub); wrap_assert( !status, "Failed to set upper bound." ); } void MIP_cplex_wrapper::setVarLB(int iVar, double lb) { char cl = 'L'; status = dll_CPXchgbds (env, lp, 1, &iVar, &cl, &lb); wrap_assert( !status, "Failed to set lower bound." ); } void MIP_cplex_wrapper::setVarUB(int iVar, double ub) { char cu = 'U'; status = dll_CPXchgbds (env, lp, 1, &iVar, &cu, &ub); wrap_assert( !status, "Failed to set upper bound." ); } /// SolutionCallback ------------------------------------------------------------------------ /// CPLEX ensures thread-safety static int CPXPUBLIC solcallback (CPXCENVptr env, void *cbdata, int wherefrom, void *cbhandle) { int status = 0; MIP_wrapper::CBUserInfo *info = (MIP_wrapper::CBUserInfo*) cbhandle; MIP_cplex_wrapper* cw = static_cast(info->wrapper); int hasincumbent = 0; int newincumbent = 0; double objVal; status = cw->dll_CPXgetcallbackinfo (env, cbdata, wherefrom, CPX_CALLBACK_INFO_NODE_COUNT, &info->pOutput->nNodes); if ( status ) goto TERMINATE; status = cw->dll_CPXgetcallbackinfo (env, cbdata, wherefrom, CPX_CALLBACK_INFO_NODES_LEFT, &info->pOutput->nOpenNodes); if ( status ) goto TERMINATE; status = cw->dll_CPXgetcallbackinfo (env, cbdata, wherefrom, CPX_CALLBACK_INFO_MIP_FEAS, &hasincumbent); if ( status ) goto TERMINATE; if ( hasincumbent ) { status = cw->dll_CPXgetcallbackinfo (env, cbdata, wherefrom, CPX_CALLBACK_INFO_BEST_INTEGER, &objVal); if ( status ) goto TERMINATE; if ( fabs(info->pOutput->objVal - objVal) > 1e-12*(1.0 + fabs(objVal)) ) { newincumbent = 1; info->pOutput->objVal = objVal; info->pOutput->status = MIP_wrapper::SAT; info->pOutput->statusName = "feasible from a callback"; } } // if ( nodecnt >= info->lastlog + 100 || newincumbent ) { // double walltime; // double dettime; status = cw->dll_CPXgetcallbackinfo (env, cbdata, wherefrom, CPX_CALLBACK_INFO_BEST_REMAINING, &info->pOutput->bestBound); // if ( status ) goto TERMINATE; // status = dll_CPXgettime (env, &walltime); // if ( status ) goto TERMINATE; // // status = dll_CPXgetdettime (env, &dettime); // if ( status ) goto TERMINATE; // // } if ( newincumbent ) { assert(info->pOutput->x); status = cw->dll_CPXgetcallbackincumbent (env, cbdata, wherefrom, (double*)info->pOutput->x, 0, info->pOutput->nCols-1); if ( status ) goto TERMINATE; info->pOutput->dWallTime = std::chrono::duration( std::chrono::steady_clock::now() - info->pOutput->dWallTime0).count(); info->pOutput->dCPUTime = double(std::clock() - info->pOutput->cCPUTime0) / CLOCKS_PER_SEC; /// Call the user function: if (info->solcbfn) (*info->solcbfn)(*info->pOutput, info->psi); info->printed = true; } TERMINATE: return (status); } /* END logcallback */ // end SolutionCallback --------------------------------------------------------------------- /// Cut callbacks, mostly copied from admipex5.c, CPLEX 12.6.3 /* The following macro defines the smallest improvement on the value of the objective function that is required when adding user cuts from within a callback. If the improvement on the value of the ojective function is not large enough, the callback will abort the cut loop. */ #define EPSOBJ 0.1 /* The following structure will hold the information we need to pass to the cut callback function */ struct cutinfo { CPXLPptr lp; int numcols; int num; double *x; int *beg; int *ind; double *val; double *rhs; int nodeid; double nodeobjval; int objsen; MIP_wrapper::CBUserInfo *info=0; }; typedef struct cutinfo CUTINFO, *CUTINFOptr; /* Init information on the node objval for the user cut callback */ static void initnodeobjvalinfo (MIP_cplex_wrapper* cw, CPXENVptr env, CPXLPptr lp, CUTINFOptr cutinfo) { cutinfo->nodeid = -1; cutinfo->nodeobjval = 0.0; cutinfo->objsen = cw->dll_CPXgetobjsen (env, lp); if ( cutinfo->objsen == CPX_MIN ) cutinfo->objsen = 1; else cutinfo->objsen = -1; } /* END initnodeobjvalinfo */ static int CPXPUBLIC myusercutcallback (CPXCENVptr env, void *cbdata, int wherefrom, void *cbhandle, int *useraction_p) { int status = 0; CUTINFOptr cutinfo = (CUTINFOptr) cbhandle; // int numcols = cutinfo->numcols; // int numcuts = cutinfo->num; // double *x = cutinfo->x; // int *beg = cutinfo->beg; // int *ind = cutinfo->ind; // double *val = cutinfo->val; // double *rhs = cutinfo->rhs; // int *cutind = NULL; // double *cutval = NULL; // double cutvio; int addedcuts = 0; // int i, j, k; //, cutnz; MIP_wrapper::CBUserInfo *info = cutinfo->info; MIP_cplex_wrapper* cw = static_cast(info->wrapper); // double *x = info->pCutOutput->x; *useraction_p = CPX_CALLBACK_DEFAULT; /* If we are called as a user cut callback, decide first if we want to add cuts or abort the cut loop. When adding user cuts with purgeable flag set to CPX_USECUT_PURGE or CPX_USECUT_FILTER, it is important to avoid the possibility of an infinite cut loop, where the same cuts are added to the LP and then immediately purged at every cut pass. Such a situation can be avoided, for instance, by applying a tailing off criterion and aborting the cut loop where no progress in the objval is observed. Note, however, that the same approach must not be applied with lazy constraints. In this case, if lazy constraints are added with purgeable flag set to CPX_USECUT_PURGE, adding the same lazy constraint more than once could be required to ensure the correctness of the final result. */ bool fMIPSol=true; if ( wherefrom == CPX_CALLBACK_MIP_CUT_LOOP || wherefrom == CPX_CALLBACK_MIP_CUT_LAST ) { int oldnodeid = cutinfo->nodeid; double oldnodeobjval = cutinfo->nodeobjval; fMIPSol = false; /* Retrieve nodeid and node objval of the current node */ status = cw->dll_CPXgetcallbacknodeinfo (env, cbdata, wherefrom, 0, CPX_CALLBACK_INFO_NODE_SEQNUM, &cutinfo->nodeid); if ( status ) { fprintf(stderr, "Failed to get node id.\n"); goto TERMINATE; } status = cw->dll_CPXgetcallbacknodeinfo (env, cbdata, wherefrom, 0, CPX_CALLBACK_INFO_NODE_OBJVAL, &cutinfo->nodeobjval); if ( status ) { fprintf(stderr, "Failed to get node objval.\n"); goto TERMINATE; } /* Abort the cut loop if we are stuck at the same node as before and there is no progress in the node objval */ if ( oldnodeid == cutinfo->nodeid ) { double objchg = (cutinfo->nodeobjval - oldnodeobjval); /* Multiply objchg by objsen to normalize the change in the objective function to the case of a minimization problem */ objchg *= cutinfo->objsen; if ( objchg <= EPSOBJ ) { *useraction_p = CPX_CALLBACK_ABORT_CUT_LOOP; goto TERMINATE; } } } /* If we reached this point, we are .. in a lazyconstraint callback, or .. in a user cut callback, and cuts seem to help improving the node objval. In both cases, we retrieve the x solution and look for violated cuts. */ if ( info->cutcbfn ) { // if cut handler given MIP_wrapper::Output outpRlx; outpRlx.x = info->pOutput->x; // using the sol output storage TODO? outpRlx.nCols = info->pOutput->nCols; assert( outpRlx.x && outpRlx.nCols ); status = cw->dll_CPXgetcallbacknodex (env, cbdata, wherefrom, (double*)outpRlx.x, 0, outpRlx.nCols-1); if ( status ) { fprintf(stderr, "Cut callback: failed to get node solution.\n"); goto TERMINATE; } MIP_wrapper::CutInput cutInput; info->cutcbfn( outpRlx, cutInput, info->psi, fMIPSol ); static int nCuts=0; nCuts += cutInput.size(); // if ( cutInput.size() ) // cerr << "\n N CUTS: " << nCuts << endl; for ( auto& cd : cutInput ) { if ( ! ( cd.mask & (MIP_wrapper::MaskConsType_Usercut|MIP_wrapper::MaskConsType_Lazy) ) ) throw runtime_error( "Cut callback: should be user/lazy" ); /* Use a cut violation tolerance of 0.01 */ if ( true ) { //cutvio > 0.01 ) { status = cw->dll_CPXcutcallbackadd (env, cbdata, wherefrom, cd.rmatind.size(), cd.rhs, getCPLEXConstrSense(cd.sense), cd.rmatind.data(), cd.rmatval.data(), CPX_USECUT_FORCE); // PURGE? if ( status ) { fprintf (stderr, "CPLEX callback: failed to add cut.\n"); goto TERMINATE; } addedcuts++; } } } /* Tell CPLEX that cuts have been created */ if ( addedcuts > 0 ) { *useraction_p = CPX_CALLBACK_SET; } TERMINATE: return (status); } /* END myusercutcallback */ // ----------------- END Cut callbacks ------------------ MIP_cplex_wrapper::Status MIP_cplex_wrapper::convertStatus(int cplexStatus) { Status s = Status::UNKNOWN; /* Converting the status. */ switch(cplexStatus) { case CPXMIP_OPTIMAL: s = Status::OPT; wrap_assert(dll_CPXgetsolnpoolnumsolns(env, lp), "Optimality reported but pool empty?", false); break; case CPXMIP_INFEASIBLE: s = Status::UNSAT; break; // case CPXMIP_OPTIMAL_INFEAS: case CPXMIP_INForUNBD: s = Status::UNSATorUNBND; break; case CPXMIP_SOL_LIM: case CPXMIP_NODE_LIM_FEAS: case CPXMIP_TIME_LIM_FEAS: case CPXMIP_FAIL_FEAS: case CPXMIP_MEM_LIM_FEAS: case CPXMIP_ABORT_FEAS: case CPXMIP_FAIL_FEAS_NO_TREE: s = Status::SAT; wrap_assert(dll_CPXgetsolnpoolnumsolns(env, lp), "Feasibility reported but pool empty?", false); break; case CPXMIP_UNBOUNDED: s = Status::UNBND; break; // case CPXMIP_ABORT_INFEAS: case CPXMIP_FAIL_INFEAS: s = Status::__ERROR; break; default: // case CPXMIP_OPTIMAL_TOL: // case CPXMIP_ABORT_RELAXATION_UNBOUNDED: if (dll_CPXgetsolnpoolnumsolns (env, lp)) s = Status::SAT; else s = Status::UNKNOWN; } return s; } void msgfunction(void *handle, const char *msg_string) { cerr << msg_string << flush; } void MIP_cplex_wrapper::solve() { // Move into ancestor? /////////////// Last-minute solver options ////////////////// if ( options->flag_all_solutions && 0==nProbType ) cerr << "WARNING. --all-solutions for SAT problems not implemented." << endl; // Before all manual params ??? if (options->sReadParams.size()) { status = dll_CPXreadcopyparam (env, options->sReadParams.c_str()); wrap_assert(!status, "Failed to read CPLEX parameters.", false); } /* Turn on output to the screen */ if (fVerbose) { CPXCHANNELptr chnl[4]; dll_CPXgetchannels(env, &chnl[0], &chnl[1], &chnl[2], &chnl[3]); for (int i = 0; i < 3; ++i) { status = dll_CPXaddfuncdest(env, chnl[i], nullptr, msgfunction); } // status = dll_CPXsetintparam(env, CPXPARAM_ScreenOutput, // fVerbose ? CPX_ON : CPX_OFF); // also when flag_all_solutions? TODO // wrap_assert(!status, " CPLEX Warning: Failure to switch screen indicator.", false); } status = dll_CPXsetintparam (env, CPXPARAM_MIP_Display, fVerbose ? 2 : 0); // also when flag_all_solutions? TODO wrap_assert(!status, " CPLEX Warning: Failure to switch logging.", false); /// Make it wall time by default, 12.8 // status = dll_CPXsetintparam (env, CPXPARAM_ClockType, 1); // CPU time // wrap_assert(!status, " CPLEX Warning: Failure to measure CPU time.", false); status = dll_CPXsetintparam (env, CPX_PARAM_MIPCBREDLP, CPX_OFF); // Access original model wrap_assert(!status, " CPLEX Warning: Failure to set access original model in callbacks.", false); if (options->sExportModel.size()) { status = dll_CPXwriteprob (env, lp, options->sExportModel.c_str(), NULL); wrap_assert(!status, "Failed to write LP to disk.", false); } /// TODO // if(all_solutions && obj.getImpl()) { // IloNum lastObjVal = (obj.getSense() == IloObjective::Minimize ) ? // _ilocplex->use(SolutionCallback(_iloenv, lastObjVal, *this)); // Turn off CPLEX logging if (options->nThreads>0) { status = dll_CPXsetintparam (env, CPXPARAM_Threads, options->nThreads); wrap_assert(!status, "Failed to set CPXPARAM_Threads.", false); } if (options->nTimeout>0) { status = dll_CPXsetdblparam (env, CPXPARAM_TimeLimit, static_cast(options->nTimeout)/1000.0); wrap_assert(!status, "Failed to set CPXPARAM_TimeLimit.", false); } if (options->nSolLimit>0) { status = dll_CPXsetintparam (env, CPXPARAM_MIP_Limits_Solutions, options->nSolLimit); wrap_assert(!status, "Failed to set CPXPARAM_MIP_Limits_Solutions.", false); } if (options->nSeed>=0) { status = dll_CPXsetintparam (env, CPXPARAM_RandomSeed, options->nSeed); wrap_assert(!status, "Failed to set CPXPARAM_RandomSeed.", false); } if (options->nMIPFocus>0) { status = dll_CPXsetintparam (env, CPXPARAM_Emphasis_MIP, options->nMIPFocus); wrap_assert(!status, "Failed to set CPXPARAM_Emphasis_MIP.", false); } if (options->nWorkMemLimit>0) { status = dll_CPXsetintparam (env, CPXPARAM_MIP_Strategy_File, 3); wrap_assert(!status, "Failed to set CPXPARAM_MIP_Strategy_File.", false); status = dll_CPXsetdblparam (env, CPXPARAM_WorkMem, 1024.0 * options->nWorkMemLimit); // MB in CPLEX wrap_assert(!status, "Failed to set CPXPARAM_WorkMem.", false); } if (options->sNodefileDir.size()>0) { status = dll_CPXsetstrparam (env, CPXPARAM_WorkDir, options->sNodefileDir.c_str()); wrap_assert(!status, "Failed to set CPXPARAM_WorkDir.", false); } if ( options->absGap>=0.0 ) { status = dll_CPXsetdblparam (env, CPXPARAM_MIP_Tolerances_AbsMIPGap, options->absGap); wrap_assert(!status, "Failed to set CPXPARAM_MIP_Tolerances_AbsMIPGap.", false); } if (options->relGap>=0.0) { status = dll_CPXsetdblparam (env, CPXPARAM_MIP_Tolerances_MIPGap, options->relGap); wrap_assert(!status, "Failed to set CPXPARAM_MIP_Tolerances_MIPGap.", false); } if (options->intTol>=0.0) { status = dll_CPXsetdblparam (env, CPXPARAM_MIP_Tolerances_Integrality, options->intTol); wrap_assert(!status, "Failed to set CPXPARAM_MIP_Tolerances_Integrality.", false); } // status = dll_CPXsetdblparam (env, CPXPARAM_MIP_Tolerances_ObjDifference, objDiff); // wrap_assert(!status, "Failed to set CPXPARAM_MIP_Tolerances_ObjDifference.", false); /// Solution callback output.nCols = colObj.size(); x.resize(output.nCols); output.x = &x[0]; if (options->flag_all_solutions && cbui.solcbfn) { status = dll_CPXsetinfocallbackfunc (env, solcallback, &cbui); wrap_assert(!status, "Failed to set solution callback", false); } if ( cbui.cutcbfn ) { assert( cbui.cutMask & (MaskConsType_Usercut|MaskConsType_Lazy) ); if ( cbui.cutMask & MaskConsType_Usercut ) { // For user cuts, needs to keep some info after presolve if ( fVerbose ) cerr << " MIP_cplex_wrapper: user cut callback enabled, setting params" << endl; CUTINFO usercutinfo; // THREADS? TODO usercutinfo.info = &cbui; /* Init information on the node objval for the user cut callback */ initnodeobjvalinfo (this, env, lp, &usercutinfo); /* Assure linear mappings between the presolved and original models */ status = dll_CPXsetintparam (env, CPXPARAM_Preprocessing_Linear, 0); wrap_assert ( !status, "CPLEX: setting prepro_linear" ); /* Turn on traditional search for use with control callbacks */ status = dll_CPXsetintparam (env, CPXPARAM_MIP_Strategy_Search, CPX_MIPSEARCH_TRADITIONAL); wrap_assert ( !status, "CPLEX: setting traditional search" ); /* Let MIP callbacks work on the original model */ status = dll_CPXsetintparam (env, CPXPARAM_MIP_Strategy_CallbackReducedLP, CPX_OFF); wrap_assert ( !status, "CPLEX: setting callbacks to work on orig model" ); /// And /* Set up to use MIP usercut callback */ status = dll_CPXsetusercutcallbackfunc (env, myusercutcallback, &usercutinfo); wrap_assert ( !status, "CPLEX: setting user cut callback" ); } if ( cbui.cutMask & MaskConsType_Lazy ) { if ( fVerbose ) cerr << " MIP_cplex_wrapper: lazy cut callback enabled, setting params" << endl; CUTINFO lazyconinfo; lazyconinfo.info = &cbui; /* Init information on the node objval for the user cut callback. No need to initialize the information on the node objval, for the lazy constraint callback, because those information are used only in the user cut callback. */ initnodeobjvalinfo (this, env, lp, &lazyconinfo); /* Assure linear mappings between the presolved and original models */ status = dll_CPXsetintparam (env, CPXPARAM_Preprocessing_Linear, 0); wrap_assert ( !status, "CPLEX: setting prepro_linear" ); /* Turn on traditional search for use with control callbacks */ // status = dll_CPXsetintparam (env, CPXPARAM_MIP_Strategy_Search, // CPX_MIPSEARCH_TRADITIONAL); // wrap_assert ( !status, "CPLEX: setting traditional search" ); /* Let MIP callbacks work on the original model */ status = dll_CPXsetintparam (env, CPXPARAM_MIP_Strategy_CallbackReducedLP, CPX_OFF); wrap_assert ( !status, "CPLEX: setting callbacks to work on orig model" ); /* Set up to use MIP lazyconstraint callback. The callback funtion * registered is the same, but the data will be different. */ status = dll_CPXsetlazyconstraintcallbackfunc (env, myusercutcallback, &lazyconinfo); wrap_assert ( !status, "CPLEX: setting lazy cut callback" ); } } /// after all modifs if (options->sWriteParams.size()) { status = dll_CPXwriteparam (env, options->sWriteParams.c_str()); wrap_assert(!status, "Failed to write CPLEX parameters.", false); } // status = dll_CPXgettime (env, &output.dCPUTime); // wrap_assert(!status, "Failed to get time stamp.", false); cbui.pOutput->dWallTime0 = output.dWallTime0 = std::chrono::steady_clock::now(); cbui.pOutput->cCPUTime0 = std::clock(); /* Optimize the problem and obtain solution. */ status = dll_CPXmipopt (env, lp); wrap_assert( !status, "Failed to optimize MIP." ); output.dWallTime = std::chrono::duration( std::chrono::steady_clock::now() - output.dWallTime0).count(); double tmNow = std::clock(); // status = dll_CPXgettime (env, &tmNow); Buggy in 12.7.1.0 wrap_assert(!status, "Failed to get time stamp.", false); output.dCPUTime = (tmNow - cbui.pOutput->cCPUTime0) / CLOCKS_PER_SEC; int solstat = dll_CPXgetstat (env, lp); output.status = convertStatus(solstat); output.statusName = dll_CPXgetstatstring (env, solstat, cplex_status_buffer); /// Continuing to fill the output object: if (Status::OPT == output.status || Status::SAT ==output.status) { status = dll_CPXgetobjval (env, lp, &output.objVal); wrap_assert( !status, "No MIP objective value available." ); /* The size of the problem should be obtained by asking CPLEX what the actual size is, rather than using what was passed to CPXcopylp. cur_numrows and cur_numcols store the current number of rows and columns, respectively. */ // ?????????????? TODO // int cur_numrows = dll_CPXgetnumrows (env, lp); int cur_numcols = dll_CPXgetnumcols (env, lp); assert(cur_numcols == colObj.size()); x.resize(cur_numcols); output.x = &x[0]; status = dll_CPXgetx (env, lp, &x[0], 0, cur_numcols-1); wrap_assert(!status, "Failed to get variable values."); if (cbui.solcbfn /*&& (!options->flag_all_solutions || !cbui.printed)*/) { cbui.solcbfn(output, cbui.psi); } } output.bestBound = 1e308; status = dll_CPXgetbestobjval (env, lp, &output.bestBound); wrap_assert(!status, "Failed to get the best bound.", false); output.nNodes = dll_CPXgetnodecnt (env, lp); output.nOpenNodes = dll_CPXgetnodeleftcnt (env, lp); } void MIP_cplex_wrapper::setObjSense(int s) { status = dll_CPXchgobjsen (env, lp, -s); // +1 for min in CPLEX wrap_assert(!status, "Failed to set obj sense."); } libminizinc-2.4.2/solvers/MIP/MIP_gurobi_solverfactory.cpp000066400000000000000000000006521360574160400236430ustar00rootroot00000000000000#include #include #include namespace MiniZinc { namespace { void getWrapper() { static MIP_SolverFactory _gurobi_solver_factory; return; } } Gurobi_SolverFactoryInitialiser::Gurobi_SolverFactoryInitialiser(void) { getWrapper(); } } libminizinc-2.4.2/solvers/MIP/MIP_gurobi_wrap.cpp000066400000000000000000001011101360574160400217010ustar00rootroot00000000000000// * -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef GUROBI_PLUGIN #ifdef HAS_DLFCN_H #include #elif defined HAS_WINDOWS_H #include #endif #endif using namespace std; #include #include string MIP_gurobi_wrapper::getDescription(MiniZinc::SolverInstanceBase::Options* opt) { ostringstream oss; oss << "MIP wrapper for Gurobi library " << getVersion(); oss << ". Compiled " __DATE__ " " __TIME__; return oss.str(); } string MIP_gurobi_wrapper::getVersion(MiniZinc::SolverInstanceBase::Options* opt) { ostringstream oss; MIP_gurobi_wrapper mgw( nullptr ); // to avoid opening the env try { mgw.checkDLL(); int major, minor, technical; mgw.dll_GRBversion(&major, &minor, &technical); oss << major << '.' << minor << '.' << technical; return oss.str(); } catch (MiniZinc::InternalError&) { return ""; } } string MIP_gurobi_wrapper::needDllFlag( ) { MIP_gurobi_wrapper mgw( NULL ); try { mgw.checkDLL(); return ""; } catch (MiniZinc::InternalError&) { return "--gurobi-dll"; } } string MIP_gurobi_wrapper::getId() { return "gurobi"; } string MIP_gurobi_wrapper::getName() { return "Gurobi"; } vector MIP_gurobi_wrapper::getTags() { return {"mip","float","api"}; } vector MIP_gurobi_wrapper::getStdFlags() { return {"-a", "-n", "-p", "-s", "-v"}; } const vector& gurobiDLLs(void) { static const vector sGurobiDLLs = { "gurobi90", "gurobi85", "gurobi81", "gurobi80", "gurobi75", "gurobi70", "gurobi65" }; return sGurobiDLLs; } void MIP_gurobi_wrapper::Options::printHelp(ostream& os) { os << "GUROBI MIP wrapper options:" << std::endl // -s print statistics // << " --readParam read GUROBI parameters from file // << "--writeParam write GUROBI parameters to file // << "--tuneParam instruct GUROBI to tune parameters instead of solving << " -f\n free search (default)" << std::endl << " --fixed-search\n fixed search (approximation of the model's one by branching priorities)" << std::endl << " --uniform-search\n 'more fixed' search (all variables in the search anns get priority 1)" << std::endl << " --mipfocus \n 1: feasibility, 2: optimality, 3: move bound (default is 0, balanced)" << std::endl << " -a\n print intermediate solutions (use for optimization problems only TODO)" << std::endl << " -p \n use N threads, default: 1." << std::endl // << " --nomippresolve disable MIP presolving NOT IMPL" << std::endl << " --solver-time-limit , --solver-time\n" " stop search after N milliseconds wall time" << std::endl << " --solver-time-limit-feas , --solver-tlf\n" " stop search after N milliseconds wall time after the first feasible solution" << std::endl << " -n , --num-solutions \n" " stop search after N solutions" << std::endl << " -r , --random-seed \n" " random seed, integer" << std::endl << " --workmem , --nodefilestart \n" " maximal RAM for node tree used before writing to node file, GB, default: 0.5" << std::endl << " --nodefiledir \n" " nodefile directory" << std::endl << " --writeModel \n write model to (.lp, .mps, .sav, ...)" << std::endl << " --readParam \n read GUROBI parameters from file" << std::endl << " --writeParam \n write GUROBI parameters to file" << std::endl // << " --tuneParam instruct GUROBI to tune parameters instead of solving NOT IMPL" << "\n --absGap \n absolute gap |primal-dual| to stop" << std::endl << " --relGap \n relative gap |primal-dual|/ to stop. Default 1e-8, set <0 to use backend's default" << std::endl << " --feasTol \n primal feasibility tolerance. Default 1e-8" << std::endl << " --intTol \n integrality tolerance for a variable. Gurobi recommends at least feasTol. Default 1e-8" << std::endl // << " --objDiff objective function discretization. Default 1.0" << std::endl << "\n --gurobi-dll or \n Gurobi DLL, or base name, such as gurobi75, when using plugin. Default range tried: " << gurobiDLLs().front() << " .. " << gurobiDLLs().back() << std::endl << std::endl; } bool MIP_gurobi_wrapper::Options::processOption(int& i, std::vector& argv) { MiniZinc::CLOParser cop( i, argv ); if ( string(argv[i])=="-a" || string(argv[i])=="--all" || string(argv[i])=="--all-solutions" ) { flag_all_solutions = true; } else if (string(argv[i])=="-f") { } else if (string(argv[i])=="--fixed-search") { nFreeSearch = 0; } else if (string(argv[i])=="--uniform-search") { nFreeSearch = 2; } else if ( cop.get( "--mipfocus --mipFocus --MIPFocus --MIPfocus", &nMIPFocus ) ) { } else if ( cop.get( "--writeModel", &sExportModel ) ) { } else if ( cop.get( "-p", &nThreads ) ) { } else if ( cop.get( "--solver-time-limit --solver-time", &nTimeout1000 ) ) { } else if ( cop.get( "--solver-time-limit-feas --solver-tlf", &nTimeoutFeas1000 ) ) { } else if ( cop.get( "-n --num-solutions", &nSolLimit ) ) { } else if ( cop.get( "-r --random-seed", &nSeed ) ) { } else if ( cop.get( "--workmem --nodefilestart", &nWorkMemLimit ) ) { } else if ( cop.get( "--nodefiledir --NodefileDir", &sNodefileDir ) ) { } else if ( cop.get( "--readParam", &sReadParams ) ) { } else if ( cop.get( "--writeParam", &sWriteParams ) ) { } else if ( cop.get( "--absGap", &absGap ) ) { } else if ( cop.get( "--relGap", &relGap ) ) { } else if ( cop.get( "--feasTol", &feasTol ) ) { } else if ( cop.get( "--intTol", &intTol ) ) { } else if ( cop.get( "--gurobi-dll", &sGurobiDLL ) ) { // } else if ( cop.get( "--objDiff", &objDiff ) ) { } else return false; return true; } void MIP_gurobi_wrapper::wrap_assert(bool cond, string msg, bool fTerm) { if ( !cond ) { gurobi_buffer = "[NO ERROR STRING GIVEN]"; if (error) { gurobi_buffer = dll_GRBgeterrormsg(env); } string msgAll = (" MIP_gurobi_wrapper runtime error: " + gurobi_buffer + "\nMessage from caller: " + msg); cerr << msgAll << "\nGurobi error code: " << error << endl; if (fTerm) { cerr << "TERMINATING." << endl; throw runtime_error(msgAll); } } } #ifdef GUROBI_PLUGIN namespace { void* dll_open(const char* file) { #ifdef HAS_DLFCN_H if (MiniZinc::FileUtils::is_absolute(file)) { return dlopen( file, RTLD_NOW); } else { return dlopen( (std::string("lib")+file+".so").c_str(), RTLD_NOW); } #else if (MiniZinc::FileUtils::is_absolute(file)) { return LoadLibrary(file); } else { return LoadLibrary((std::string(file)+".dll").c_str()); } #endif } void* dll_sym(void* dll, const char* sym) { #ifdef HAS_DLFCN_H void* ret = dlsym(dll, sym); #else void* ret = GetProcAddress((HMODULE)dll, sym); #endif if (ret==NULL) throw MiniZinc::InternalError("cannot load symbol "+string(sym)+" from gurobi dll"); return ret; } void dll_close(void* dll) { #ifdef HAS_DLFCN_H dlclose(dll); #else FreeLibrary((HMODULE)dll); #endif } } #endif void MIP_gurobi_wrapper::checkDLL() { #ifdef GUROBI_PLUGIN gurobi_dll = NULL; if ( options && options->sGurobiDLL.size() ) { gurobi_dll = dll_open( options->sGurobiDLL.c_str() ); } else { for( const auto& s: gurobiDLLs() ) { gurobi_dll = dll_open( s.c_str() ); if ( NULL!=gurobi_dll ) { break; } } } if (gurobi_dll==NULL) { if (options==NULL || options->sGurobiDLL.empty()) { throw MiniZinc::InternalError("cannot load gurobi dll, specify --gurobi-dll"); } else { throw MiniZinc::InternalError("cannot load gurobi dll `"+options->sGurobiDLL+"'"); } } *(void**)(&dll_GRBversion) = dll_sym(gurobi_dll, "GRBversion"); *(void**)(&dll_GRBaddconstr) = dll_sym(gurobi_dll, "GRBaddconstr"); *(void**)(&dll_GRBaddgenconstrIndicator) = dll_sym(gurobi_dll, "GRBaddgenconstrIndicator"); *(void**)(&dll_GRBaddvars) = dll_sym(gurobi_dll, "GRBaddvars"); *(void**)(&dll_GRBcbcut) = dll_sym(gurobi_dll, "GRBcbcut"); *(void**)(&dll_GRBcbget) = dll_sym(gurobi_dll, "GRBcbget"); *(void**)(&dll_GRBcblazy) = dll_sym(gurobi_dll, "GRBcblazy"); *(void**)(&dll_GRBfreeenv) = dll_sym(gurobi_dll, "GRBfreeenv"); *(void**)(&dll_GRBfreemodel) = dll_sym(gurobi_dll, "GRBfreemodel"); *(void**)(&dll_GRBgetdblattr) = dll_sym(gurobi_dll, "GRBgetdblattr"); *(void**)(&dll_GRBgetdblattrarray) = dll_sym(gurobi_dll, "GRBgetdblattrarray"); *(void**)(&dll_GRBgetenv) = dll_sym(gurobi_dll, "GRBgetenv"); *(void**)(&dll_GRBgeterrormsg) = dll_sym(gurobi_dll, "GRBgeterrormsg"); *(void**)(&dll_GRBgetintattr) = dll_sym(gurobi_dll, "GRBgetintattr"); *(void**)(&dll_GRBloadenv) = dll_sym(gurobi_dll, "GRBloadenv"); *(void**)(&dll_GRBnewmodel) = dll_sym(gurobi_dll, "GRBnewmodel"); *(void**)(&dll_GRBoptimize) = dll_sym(gurobi_dll, "GRBoptimize"); *(void**)(&dll_GRBreadparams) = dll_sym(gurobi_dll, "GRBreadparams"); *(void**)(&dll_GRBsetcallbackfunc) = dll_sym(gurobi_dll, "GRBsetcallbackfunc"); *(void**)(&dll_GRBsetdblparam) = dll_sym(gurobi_dll, "GRBsetdblparam"); *(void**)(&dll_GRBsetintattr) = dll_sym(gurobi_dll, "GRBsetintattr"); *(void**)(&dll_GRBsetintattrlist) = dll_sym(gurobi_dll, "GRBsetintattrlist"); *(void**)(&dll_GRBsetdblattrelement) = dll_sym(gurobi_dll, "GRBsetdblattrelement"); *(void**)(&dll_GRBsetdblattrlist) = dll_sym(gurobi_dll, "GRBsetdblattrlist"); *(void**)(&dll_GRBsetintparam) = dll_sym(gurobi_dll, "GRBsetintparam"); *(void**)(&dll_GRBsetstrparam) = dll_sym(gurobi_dll, "GRBsetstrparam"); *(void**)(&dll_GRBterminate) = dll_sym(gurobi_dll, "GRBterminate"); *(void**)(&dll_GRBupdatemodel) = dll_sym(gurobi_dll, "GRBupdatemodel"); *(void**)(&dll_GRBwrite) = dll_sym(gurobi_dll, "GRBwrite"); *(void**)(&dll_GRBwriteparams) = dll_sym(gurobi_dll, "GRBwriteparams"); #else dll_GRBversion = GRBversion; dll_GRBaddconstr = GRBaddconstr; dll_GRBaddgenconstrIndicator = GRBaddgenconstrIndicator; dll_GRBaddvars = GRBaddvars; dll_GRBcbcut = GRBcbcut; dll_GRBcbget = GRBcbget; dll_GRBcblazy = GRBcblazy; dll_GRBfreeenv = GRBfreeenv; dll_GRBfreemodel = GRBfreemodel; dll_GRBgetdblattr = GRBgetdblattr; dll_GRBgetdblattrarray = GRBgetdblattrarray; dll_GRBgetenv = GRBgetenv; dll_GRBgeterrormsg = GRBgeterrormsg; dll_GRBgetintattr = GRBgetintattr; dll_GRBloadenv = GRBloadenv; dll_GRBnewmodel = GRBnewmodel; dll_GRBoptimize = GRBoptimize; dll_GRBreadparams = GRBreadparams; dll_GRBsetcallbackfunc = GRBsetcallbackfunc; dll_GRBsetdblparam = GRBsetdblparam; dll_GRBsetintattr = GRBsetintattr; dll_GRBsetintattrlist = GRBsetintattrlist; dll_GRBsetdblattrelement = GRBsetdblattrelement; dll_GRBsetdblattrlist = GRBsetdblattrlist; dll_GRBsetintparam = GRBsetintparam; dll_GRBsetstrparam = GRBsetstrparam; dll_GRBterminate = GRBterminate; dll_GRBupdatemodel = GRBupdatemodel; dll_GRBwrite = GRBwrite; dll_GRBwriteparams = GRBwriteparams; #endif } void MIP_gurobi_wrapper::openGUROBI() { checkDLL(); /* Initialize the GUROBI environment */ { // cout << "% " << flush; // Gurobi 7.5.2 prints "Academic License..." MiniZinc::StreamRedir redirStdout(stdout, stderr); error = dll_GRBloadenv (&env, "mzn-gurobi.log"); } wrap_assert ( !error, "Could not open GUROBI environment." ); error = dll_GRBsetintparam(env, "OutputFlag", 0); // Switch off output // error = dll_GRBsetintparam(env, "LogToConsole", // fVerbose ? 1 : 0); // also when flag_all_solutions? TODO /* Create the problem. */ error = dll_GRBnewmodel(env, &model, "mzn_gurobi", 0, NULL, NULL, NULL, NULL, NULL); wrap_assert ( model!=NULL, "Failed to create LP." ); } void MIP_gurobi_wrapper::closeGUROBI() { /* Free model */ // If not allocated, skip if (nullptr!=model) { /* Free up the problem as allocated by GRB_createprob, if necessary */ dll_GRBfreemodel(model); model = 0; } /* Free environment */ if (nullptr!=env) dll_GRBfreeenv(env); /// and at last: // MIP_wrapper::cleanup(); #ifdef GUROBI_PLUGIN // dll_close(gurobi_dll); // Is called too many times, disabling. 2019-05-06 #endif } void MIP_gurobi_wrapper::doAddVars (size_t n, double* obj, double* lb, double* ub, MIP_wrapper::VarType* vt, string *names) { /// Convert var types: vector ctype(n); vector pcNames(n); for (size_t i=0; i(n), 0, NULL, NULL, NULL, obj, lb, ub, &ctype[0], &pcNames[0]); wrap_assert( !error, "Failed to declare variables." ); error = dll_GRBupdatemodel(model); wrap_assert( !error, "Failed to update model." ); } static char getGRBSense( MIP_wrapper::LinConType s ) { switch (s) { case MIP_wrapper::LQ: return GRB_LESS_EQUAL; case MIP_wrapper::EQ: return GRB_EQUAL; case MIP_wrapper::GQ: return GRB_GREATER_EQUAL; default: throw runtime_error(" MIP_gurobi_wrapper: unknown constraint sense"); } } void MIP_gurobi_wrapper::addRow (int nnz, int* rmatind, double* rmatval, MIP_wrapper::LinConType sense, double rhs, int mask, string rowName) { //// Make sure in order to notice the indices of lazy constr: ++ nRows; /// Convert var types: char ssense=getGRBSense(sense); const char * pRName = rowName.c_str(); error = dll_GRBaddconstr(model, nnz, rmatind, rmatval, ssense, rhs, pRName); wrap_assert( !error, "Failed to add constraint." ); int nLazyAttr=0; const bool fUser = (MaskConsType_Usercut & mask) != 0; const bool fLazy = (MaskConsType_Lazy & mask) != 0; /// Gurobi 6.5.2 has lazyness 1-3. if (fUser) { if (fLazy) nLazyAttr = 2; // just active lazy else nLazyAttr = 3; // even LP-active } else if (fLazy) nLazyAttr = 1; // very lazy if (nLazyAttr) { nLazyIdx.push_back( nRows-1 ); nLazyValue.push_back( nLazyAttr ); } } void MIP_gurobi_wrapper::addIndicatorConstraint( int iBVar, int bVal, int nnz, int* rmatind, double* rmatval, MIP_wrapper::LinConType sense, double rhs, string rowName) { wrap_assert( 0<=bVal && 1>=bVal, "Gurobi: addIndicatorConstraint: bVal not 0/1" ); //// Make sure in order to notice the indices of lazy constr: also here? TODO ++ nRows; char ssense=getGRBSense(sense); error = dll_GRBaddgenconstrIndicator(model, rowName.c_str(), iBVar, bVal, nnz, rmatind, rmatval, ssense, rhs); wrap_assert( !error, "Failed to add indicator constraint." ); } bool MIP_gurobi_wrapper::addSearch( const std::vector& vars, const std::vector pri ) { assert( vars.size()==pri.size() ); static_assert( sizeof(VarId)==sizeof(int), "VarId should be (u)int currently" ); error = dll_GRBsetintattrlist(model, "BranchPriority", static_cast(vars.size()), (int*)vars.data(), (int*)pri.data()); wrap_assert( !error, "Failed to add branching priorities" ); return true; } int MIP_gurobi_wrapper::getFreeSearch() { return options->nFreeSearch; } bool MIP_gurobi_wrapper::addWarmStart( const std::vector& vars, const std::vector vals ) { assert( vars.size()==vals.size() ); static_assert( sizeof(VarId)==sizeof(int), "VarId should be (u)int currently" ); // error = GRBsetdblattrelement(model, "Start", 0, 1.0); error = dll_GRBsetdblattrlist(model, "Start", static_cast(vars.size()), (int*)vars.data(), (double*)vals.data()); wrap_assert( !error, "Failed to add warm start" ); return true; } void MIP_gurobi_wrapper::setVarBounds(int iVar, double lb, double ub) { wrap_assert( lb<=ub, "mzn-gurobi: setVarBounds: lb>ub" ); error = dll_GRBsetdblattrelement( model, GRB_DBL_ATTR_LB, iVar, lb); wrap_assert( !error, "mzn-gurobi: failed to set var lb." ); error = dll_GRBsetdblattrelement( model, GRB_DBL_ATTR_UB, iVar, ub); wrap_assert( !error, "mzn-gurobi: failed to set var ub." ); } void MIP_gurobi_wrapper::setVarLB(int iVar, double lb) { error = dll_GRBsetdblattrelement( model, GRB_DBL_ATTR_LB, iVar, lb); wrap_assert( !error, "mzn-gurobi: failed to set var lb." ); } void MIP_gurobi_wrapper::setVarUB(int iVar, double ub) { error = dll_GRBsetdblattrelement( model, GRB_DBL_ATTR_UB, iVar, ub); wrap_assert( !error, "mzn-gurobi: failed to set var ub." ); } /// SolutionCallback ------------------------------------------------------------------------ /// Gurobi ensures thread-safety static int __stdcall solcallback(GRBmodel *model, void *cbdata, int where, void *usrdata) { MIP_wrapper::CBUserInfo *info = (MIP_wrapper::CBUserInfo*) usrdata; MIP_gurobi_wrapper* gw = static_cast(info->wrapper); double nodecnt=0.0, actnodes=0.0, objVal=0.0; int solcnt=0; int newincumbent=0; if ( GRB_CB_MIP==where ) { /* General MIP callback */ gw->dll_GRBcbget(cbdata, where, GRB_CB_MIP_OBJBND, &info->pOutput->bestBound); gw->dll_GRBcbget(cbdata, where, GRB_CB_MIP_NODLFT, &actnodes); info->pOutput->nOpenNodes = static_cast(actnodes); /// Check time after the 1st feas if (-1e100!=info->nTime1Feas) { double tNow; gw->dll_GRBcbget(cbdata, where, GRB_CB_RUNTIME, (void*)&tNow); if (tNow-info->nTime1Feas >= info->nTimeoutFeas) gw->dll_GRBterminate(model); } } else if ( GRB_CB_MESSAGE==where ) { /* Message callback */ if ( info->fVerb ) { char *msg; gw->dll_GRBcbget(cbdata, where, GRB_CB_MSG_STRING, &msg); cerr << msg << flush; } } else if ( GRB_CB_MIPSOL==where ) { /* MIP solution callback */ gw->dll_GRBcbget(cbdata, where, GRB_CB_MIPSOL_NODCNT, &nodecnt); info->pOutput->nNodes = static_cast(nodecnt); gw->dll_GRBcbget(cbdata, where, GRB_CB_MIPSOL_OBJ, &objVal); gw->dll_GRBcbget(cbdata, where, GRB_CB_MIPSOL_SOLCNT, &solcnt); if ( fabs(info->pOutput->objVal - objVal) > 1e-12*(1.0 + fabs(objVal)) ) { newincumbent = 1; // Not confirmed yet, see lazy cuts // info->pOutput->objVal = objVal; // info->pOutput->status = MIP_wrapper::SAT; // info->pOutput->statusName = "feasible from a callback"; } if ( newincumbent ) { assert(info->pOutput->x); gw->dll_GRBcbget(cbdata, where, GRB_CB_MIPSOL_SOL, (void*)info->pOutput->x); info->pOutput->dWallTime = std::chrono::duration( std::chrono::steady_clock::now() - info->pOutput->dWallTime0).count(); info->pOutput->dCPUTime = double(std::clock() - info->pOutput->cCPUTime0) / CLOCKS_PER_SEC; } /// Callback for lazy cuts /// Before printing if ( info->cutcbfn && info->cutMask&MIP_wrapper::MaskConsType_Lazy ) { MIP_wrapper::CutInput cutInput; cerr << " GRB: GRB_CB_MIPSOL (" << objVal << ") -> cut callback " << endl; info->cutcbfn( *info->pOutput, cutInput, info->psi, true ); for ( auto& cd : cutInput ) { // assert( cd.mask & MIP_wrapper::MaskConsType_Lazy ); if ( cd.mask & MIP_wrapper::MaskConsType_Lazy ) { // take only lazy constr generators int error = gw->dll_GRBcblazy(cbdata, static_cast(cd.rmatind.size()), cd.rmatind.data(), cd.rmatval.data(), getGRBSense(cd.sense), cd.rhs); if (error) cerr << " GRB_wrapper: failed to add lazy cut. " << endl; else newincumbent = -1; // info->pOutput->objVal = 1e100; // to mark that we can get a new incumbent which should be printed } } } if ( solcnt>=0 /*This is solution number for Gurobi*/ && newincumbent>=0 ) { if ( fabs(info->pOutput->objVal - objVal) > 1e-12*(1.0 + fabs(objVal)) ) { newincumbent = 1; info->pOutput->objVal = objVal; info->pOutput->status = MIP_wrapper::SAT; info->pOutput->statusName = "feasible from a callback"; } } if ( newincumbent>0 ) { info->pOutput->dCPUTime = double(std::clock() - info->pOutput->cCPUTime0) / CLOCKS_PER_SEC; /// Set time for the 1st feas if (0<=info->nTimeoutFeas && -1e100==info->nTime1Feas) gw->dll_GRBcbget(cbdata, where, GRB_CB_RUNTIME, (void*)&info->nTime1Feas); /// Call the user function: if (info->solcbfn) (*info->solcbfn)(*info->pOutput, info->psi); if (0==info->nTimeoutFeas) gw->dll_GRBterminate(model); // Straight after feas } } else if ( GRB_CB_MIPNODE==where ) { int status; gw->dll_GRBcbget(cbdata, where, GRB_CB_MIPNODE_STATUS, &status); if ( status == GRB_OPTIMAL && info->cutcbfn ) { // if cut handler given MIP_wrapper::Output outpRlx; outpRlx.x = info->pOutput->x; // using the sol output storage TODO? outpRlx.nCols = info->pOutput->nCols; assert( outpRlx.x && outpRlx.nCols ); // dll_GRBcbget(cbdata, where, GRB_CB_MIPNODE_RELOBJ, outpRlx.objVal); gw->dll_GRBcbget(cbdata, where, GRB_CB_MIPNODE_REL, (void*)outpRlx.x); // cerr << " GRB: GRB_CB_MIPNODE -> cut callback " << endl; MIP_wrapper::CutInput cutInput; info->cutcbfn( outpRlx, cutInput, info->psi, false ); // static int nCuts=0; // nCuts += cutInput.size(); // if ( cutInput.size() ) // cerr << "\n N CUTS: " << nCuts << endl; for ( auto& cd : cutInput ) { if ( ! ( cd.mask & (MIP_wrapper::MaskConsType_Usercut|MIP_wrapper::MaskConsType_Lazy) ) ) throw runtime_error( "Cut callback: should be user/lazy" ); if ( cd.mask & MIP_wrapper::MaskConsType_Usercut ) { int error = gw->dll_GRBcbcut(cbdata, static_cast(cd.rmatind.size()), cd.rmatind.data(), cd.rmatval.data(), getGRBSense(cd.sense), cd.rhs); if (error) cerr << " GRB_wrapper: failed to add user cut. " << endl; } if ( cd.mask & MIP_wrapper::MaskConsType_Lazy ) { int error = gw->dll_GRBcblazy(cbdata, static_cast(cd.rmatind.size()), cd.rmatind.data(), cd.rmatval.data(), getGRBSense(cd.sense), cd.rhs); if (error) cerr << " GRB_wrapper: failed to add lazy cut. " << endl; } } } } return 0; } /* END logcallback */ // end SolutionCallback --------------------------------------------------------------------- MIP_gurobi_wrapper::Status MIP_gurobi_wrapper::convertStatus(int gurobiStatus) { Status s = Status::UNKNOWN; ostringstream oss; /* Converting the status. */ if (gurobiStatus == GRB_OPTIMAL) { s = Status::OPT; oss << "Optimal"; } else if (gurobiStatus == GRB_INF_OR_UNBD) { s = Status::UNSATorUNBND; oss << "Infeasible or unbounded"; } else if (gurobiStatus == GRB_INFEASIBLE) { s = Status::UNSAT; oss << "Infeasible"; } else if (gurobiStatus == GRB_UNBOUNDED) { oss << "Unbounded"; s = Status::UNBND; } else { int solcount=0; error = dll_GRBgetintattr(model, "SolCount", &solcount); wrap_assert(!error, " Failure to access solution count.", false); if (solcount) s = Status::SAT; oss << "Gurobi stopped with status " << gurobiStatus; } output.statusName = gurobi_status_buffer = oss.str(); return s; } void MIP_gurobi_wrapper::solve() { // Move into ancestor? if ( options->flag_all_solutions && 0==nProbType ) cerr << "WARNING. --all-solutions for SAT problems not implemented." << endl; error = dll_GRBupdatemodel(model); // for model export wrap_assert( !error, "Failed to update model." ); /// ADDING LAZY CONSTRAINTS IF ANY if ( nLazyIdx.size() ) { assert( nLazyIdx.size()==nLazyValue.size() ); if ( fVerbose ) cerr << " MIP_gurobi_wrapper: marking "<(nLazyIdx.size()), nLazyIdx.data(), nLazyValue.data()); wrap_assert( !error, "Failed to set constraint attribute." ); nLazyIdx.clear(); nLazyValue.clear(); error = dll_GRBupdatemodel(model); // for model export wrap_assert( !error, "Failed to update model after modifying some constraint attr." ); } /////////////// Last-minute solver options ////////////////// /* Turn on output to file */ error = dll_GRBsetstrparam(dll_GRBgetenv(model), "LogFile", ""); // FAILS to switch off in Ubuntu 15.04 /* Turn on output to the screen */ error = dll_GRBsetintparam(dll_GRBgetenv(model), "OutputFlag", /*fVerbose ? 1 :*/ 0); // switch off, redirect in callback // error = dll_GRBsetintparam(dll_GRBgetenv(model), "LogToConsole", // fVerbose ? 1 : 0); // also when flag_all_solutions? TODO wrap_assert(!error, " GUROBI Warning: Failure to switch screen indicator.", false); // error = dll_GRB_setintparam (env, GRB_PARAM_ClockType, 1); // CPU time // error = dll_GRB_setintparam (env, GRB_PARAM_MIP_Strategy_CallbackReducedLP, GRB__OFF); // Access original model if (options->sExportModel.size()) { error = dll_GRBwrite(model, options->sExportModel.c_str()); wrap_assert(!error, "Failed to write LP to disk.", false); } /// TODO // if(all_solutions && obj.getImpl()) { // IloNum lastObjVal = (obj.getSense() == IloObjective::Minimize ) ? // _ilogurobi->use(SolutionCallback(_iloenv, lastObjVal, *this)); // Turn off GUROBI logging if (options->nThreads>0) { error = dll_GRBsetintparam(dll_GRBgetenv(model), GRB_INT_PAR_THREADS, options->nThreads); // int nn; // THE SETTING FAILS TO WORK IN 6.0.5. // error = dll_getintparam(env, GRB_INT_PAR_THREADS, &nn); // cerr << "Set " << nThreads << " threads, reported " << nn << endl; wrap_assert(!error, "Failed to set GRB_INT_PAR_THREADS.", false); } if (options->nTimeout1000>0) { error = dll_GRBsetdblparam(dll_GRBgetenv(model), GRB_DBL_PAR_TIMELIMIT, static_cast(options->nTimeout1000)/1000.0); wrap_assert(!error, "Failed to set GRB_PARAM_TimeLimit.", false); } if (options->nSolLimit>0) { error = dll_GRBsetintparam(dll_GRBgetenv(model), GRB_INT_PAR_SOLUTIONLIMIT, options->nSolLimit); wrap_assert(!error, "Failed to set GRB_INT_PAR_SOLLIMIT.", false); } if (options->nSeed>=0) { error = dll_GRBsetintparam(dll_GRBgetenv(model), GRB_INT_PAR_SEED, options->nSeed); wrap_assert(!error, "Failed to set GRB_INT_PAR_SEED.", false); } if (options->nWorkMemLimit>0 && options->nWorkMemLimit<1e200) { error = dll_GRBsetdblparam (dll_GRBgetenv(model), "NodefileStart", options->nWorkMemLimit); wrap_assert(!error, "Failed to set NodefileStart.", false); } if (options->sNodefileDir.size()>0) { error = dll_GRBsetstrparam (dll_GRBgetenv(model), "NodefileDir", options->sNodefileDir.c_str()); wrap_assert(!error, "Failed to set NodefileDir.", false); } if ( options->absGap>=0.0 ) { error = dll_GRBsetdblparam( dll_GRBgetenv(model), "MIPGapAbs", options->absGap ); wrap_assert(!error, "Failed to set MIPGapAbs.", false); } if (options->nMIPFocus>0) { error = dll_GRBsetintparam(dll_GRBgetenv(model), GRB_INT_PAR_MIPFOCUS, options->nMIPFocus); wrap_assert(!error, "Failed to set GRB_INT_PAR_MIPFOCUS.", false); } if ( options->relGap>=0.0 ) { error = dll_GRBsetdblparam( dll_GRBgetenv(model), "MIPGap", options->relGap ); wrap_assert(!error, "Failed to set MIPGap.", false); } if ( options->intTol>=0.0 ) { error = dll_GRBsetdblparam( dll_GRBgetenv(model), "IntFeasTol", options->intTol ); wrap_assert(!error, "Failed to set IntFeasTol.", false); } if ( options->feasTol>=0.0 ) { error = dll_GRBsetdblparam( dll_GRBgetenv(model), "FeasibilityTol", options->feasTol ); wrap_assert(!error, "Failed to set FeasTol.", false); } /// Solution callback output.nCols = static_cast(colObj.size()); x.resize(output.nCols); output.x = &x[0]; SolCallbackFn solcbfn = cbui.solcbfn; if (true) { // Need for logging cbui.fVerb = fVerbose; cbui.nTimeoutFeas = options->nTimeoutFeas1000/1000.0; if ( !options->flag_all_solutions ) cbui.solcbfn = 0; if ( cbui.cutcbfn ) { assert( cbui.cutMask & (MaskConsType_Usercut|MaskConsType_Lazy) ); if ( cbui.cutMask & MaskConsType_Usercut ) { // For user cuts, needs to keep some info after presolve if ( fVerbose ) cerr << " MIP_gurobi_wrapper: user cut callback enabled, setting PreCrush=1" << endl; error = dll_GRBsetintparam(dll_GRBgetenv(model), GRB_INT_PAR_PRECRUSH, 1); wrap_assert(!error, "Failed to set GRB_INT_PAR_PRECRUSH.", false); } if ( cbui.cutMask & MaskConsType_Lazy ) { // For lazy cuts, Gurobi disables some presolves if ( fVerbose ) cerr << " MIP_gurobi_wrapper: lazy cut callback enabled, setting LazyConstraints=1" << endl; error = dll_GRBsetintparam(dll_GRBgetenv(model), GRB_INT_PAR_LAZYCONSTRAINTS, 1); wrap_assert(!error, "Failed to set GRB_INT_PAR_LAZYCONSTRAINTS.", false); } } error = dll_GRBsetcallbackfunc(model, solcallback, (void *) &cbui); wrap_assert(!error, "Failed to set callback", false); } /// after all modifs if (options->sReadParams.size()) { error = dll_GRBreadparams (dll_GRBgetenv(model), options->sReadParams.c_str()); wrap_assert(!error, "Failed to read GUROBI parameters.", false); } if (options->sWriteParams.size()) { error = dll_GRBwriteparams (dll_GRBgetenv(model), options->sWriteParams.c_str()); wrap_assert(!error, "Failed to write GUROBI parameters.", false); } cbui.pOutput->dWallTime0 = output.dWallTime0 = std::chrono::steady_clock::now(); output.dCPUTime = cbui.pOutput->cCPUTime0 = std::clock(); /* Optimize the problem and obtain solution. */ error = dll_GRBoptimize(model); wrap_assert( !error, "Failed to optimize MIP." ); output.dWallTime = std::chrono::duration( std::chrono::steady_clock::now() - output.dWallTime0).count(); output.dCPUTime = (std::clock() - output.dCPUTime) / CLOCKS_PER_SEC; int solstat; error = dll_GRBgetintattr(model, GRB_INT_ATTR_STATUS, &solstat); wrap_assert(!error, "Failed to get MIP status.", false); output.status = convertStatus(solstat); /// Continuing to fill the output object: if (Status::OPT == output.status || Status::SAT ==output.status) { error = dll_GRBgetdblattr(model, GRB_DBL_ATTR_OBJVAL, &output.objVal); wrap_assert( !error, "No MIP objective value available." ); // int cur_numrows = dll_GRB_getnumrows (env, lp); int cur_numcols = getNCols(); assert(cur_numcols == colObj.size()); x.resize(cur_numcols); output.x = &x[0]; error = dll_GRBgetdblattrarray(model, GRB_DBL_ATTR_X, 0, cur_numcols, (double*)output.x); wrap_assert(!error, "Failed to get variable values."); if ( !options->flag_all_solutions && solcbfn) { solcbfn(output, cbui.psi); } } output.bestBound = 1e308; error = dll_GRBgetdblattr(model, GRB_DBL_ATTR_OBJBOUNDC, &output.bestBound); wrap_assert(!error, "Failed to get the best bound.", false); double nNodes=-1; error = dll_GRBgetdblattr(model, GRB_DBL_ATTR_NODECOUNT, &nNodes); output.nNodes = static_cast(nNodes); output.nOpenNodes = 0; } void MIP_gurobi_wrapper::setObjSense(int s) { error = dll_GRBsetintattr(model, GRB_INT_ATTR_MODELSENSE, s>0 ? GRB_MAXIMIZE : GRB_MINIMIZE); wrap_assert(!error, "Failed to set obj sense."); } libminizinc-2.4.2/solvers/MIP/MIP_osicbc_solverfactory.cpp000066400000000000000000000006521360574160400236160ustar00rootroot00000000000000#include #include #include namespace MiniZinc { namespace { void getWrapper() { static MIP_SolverFactory _osicbc_solver_factory; return; } } OSICBC_SolverFactoryInitialiser::OSICBC_SolverFactoryInitialiser(void) { getWrapper(); } } libminizinc-2.4.2/solvers/MIP/MIP_osicbc_wrap.cpp000066400000000000000000001113261360574160400216660ustar00rootroot00000000000000// * -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #include #include #include #include #include #include using namespace std; #include #include #include #include #include #include #include #include #include #define WANT_SOLUTION string MIP_osicbc_wrapper::getDescription(MiniZinc::SolverInstanceBase::Options*) { string v = "MIP wrapper for COIN-BC "; v += CBC_VERSION; // E.g., 2.9 stable or 2.9.7 latest release v += ", using CLP "; v += CLP_VERSION; v += " Compiled " __DATE__ " " __TIME__; return v; } string MIP_osicbc_wrapper::getVersion(MiniZinc::SolverInstanceBase::Options*) { return string(CBC_VERSION)+"/"+string(CLP_VERSION); } string MIP_osicbc_wrapper::getId() { return "coin-bc"; } string MIP_osicbc_wrapper::getName() { return "COIN-BC"; } vector MIP_osicbc_wrapper::getTags() { return {"mip","float","api","osicbc","coinbc","cbc"}; } vector MIP_osicbc_wrapper::getStdFlags() { return {"-a", "-p", "-s", "-v"}; } void MIP_osicbc_wrapper::Options::printHelp(ostream& os) { os << "COIN-BC MIP wrapper options:" << std::endl // -s print statistics // << " --readParam read OSICBC parameters from file // << "--writeParam write OSICBC parameters to file // << "--tuneParam instruct OSICBC to tune parameters instead of solving << " --cbcArgs, --cbcFlags, --cbc-flags \"args\"\n" " command-line args passed to callCbc, e.g., \"-cuts off -preprocess off -passc 1\"." << std::endl // \"-preprocess off\" recommended in 2.9.6 << " --writeModel " << endl << " write model to (.mps)" << std::endl << " -a, --all\n print intermediate solutions for optimization problems\n" " (not from FeasPump. Can be slow.)" << std::endl << " -p \n use N threads, default: 1. CBC should be configured with --enable-cbc-parallel" << std::endl // << "--nomippresolve disable MIP presolving NOT IMPL" << std::endl << " --solver-time-limit \n stop search after N milliseconds" << std::endl // << "--workmem maximal amount of RAM used, MB" << std::endl // << "--readParam read OSICBC parameters from file" << std::endl // << "--writeParam write OSICBC parameters to file" << std::endl // << "--tuneParam instruct OSICBC to tune parameters instead of solving NOT IMPL" << " --absGap \n absolute gap |primal-dual| to stop" << std::endl << " --relGap \n relative gap |primal-dual|/ to stop. Default 1e-8, set <0 to use backend's default" << std::endl << " --intTol \n integrality tolerance for a variable. Default 1e-8" << std::endl // << "--objDiff objective function discretization. Default 1.0" << std::endl << std::endl; } bool MIP_osicbc_wrapper::Options::processOption(int& i, std::vector& argv) { MiniZinc::CLOParser cop( i, argv ); if ( string(argv[i])=="-a" || string(argv[i])=="--all" || string(argv[i])=="--all-solutions" ) { flag_all_solutions = true; } else if (string(argv[i])=="-f") { // std::cerr << " Flag -f: ignoring fixed strategy anyway." << std::endl; } else if ( cop.get( "--writeModel", &sExportModel ) ) { } else if ( cop.get( "-p", &nThreads ) ) { } else if ( cop.get( "--solver-time-limit", &nTimeout ) ) { } else if ( cop.get( "--workmem", &nWorkMemLimit ) ) { } else if ( cop.get( "--readParam", &sReadParams ) ) { } else if ( cop.get( "--writeParam", &sWriteParams ) ) { } else if ( cop.get( "--cbcArgs --cbcFlags --cbc-flags --solver-flags", &cbc_cmdOptions ) ) { } else if ( cop.get( "--absGap", &absGap ) ) { } else if ( cop.get( "--relGap", &relGap ) ) { } else if ( cop.get( "--intTol", &intTol ) ) { // } else if ( cop.get( "--objDiff", &objDiff ) ) { } else return false; return true; } void MIP_osicbc_wrapper::wrap_assert(bool cond, string msg, bool fTerm) { if ( !cond ) { // strcpy(osicbc_buffer, "[NO ERROR STRING GIVEN]"); // CBCgeterrorstring (env, status, osicbc_buffer); string msgAll = (" MIP_osicbc_wrapper runtime error: " + msg + " " + osicbc_buffer); cerr << msgAll << endl; if (fTerm) { cerr << "TERMINATING." << endl; throw runtime_error(msgAll); } } } void MIP_osicbc_wrapper::doAddVars (size_t n, double* obj, double* lb, double* ub, MIP_wrapper::VarType* vt, string *names) { /// Convert var types: // vector ctype(n); // vector pcNames(n); CoinPackedVector cpv; vector pCpv(n, &cpv); osi.addCols(n, pCpv.data(), lb, ub, obj); // setting integer & names later // status = CBCnewcols (env, lp, n, obj, lb, ub, &ctype[0], &pcNames[0]); // wrap_assert( !status, "Failed to declare variables." ); } void MIP_osicbc_wrapper::addRow (int nnz, int* rmatind, double* rmatval, MIP_wrapper::LinConType sense, double rhs, int mask, string rowName) { /// Convert var types: double rlb=rhs, rub=rhs; switch (sense) { case LQ: rlb = -osi.getInfinity(); break; case EQ: break; case GQ: rub = osi.getInfinity(); break; default: throw runtime_error(" MIP_wrapper: unknown constraint type"); } // ignoring mask for now. TODO // 1-by-1 too slow: // try { // CoinPackedVector cpv(nnz, rmatind, rmatval); // osi.addRow(cpv, rlb, rub); // } catch (const CoinError& err) { // cerr << " COIN-OR Error: " << err.message() << endl; // throw runtime_error(err.message()); // } /// Segfault: // rowStarts.push_back(columns.size()); // columns.insert(columns.end(), rmatind, rmatind + nnz); // element.insert(element.end(), rmatval, rmatval + nnz); rows.push_back(CoinPackedVector(nnz, rmatind, rmatval)); rowlb.push_back(rlb); rowub.push_back(rub); } bool MIP_osicbc_wrapper::addWarmStart( const std::vector& vars, const std::vector vals ) { assert( vars.size()==vals.size() ); static_assert( sizeof(VarId)==sizeof(int), "VarId should be (u)int currently" ); for (int i=0; i infeasible or you can check solver status. */ /* Return non-zero to return quickly */ //static int callBack(CbcModel * model, int whereFrom) //{ // int returnCode=0; // switch (whereFrom) { // case 1: // case 2: // if (!model->status()&&model->secondaryStatus()) // returnCode=1; // break; // case 3: // { // //CbcCompareUser compare; // //model->setNodeComparison(compare); // } // break; // case 4: // // If not good enough could skip postprocessing // break; // case 5: // break; // default: // abort(); // } // return returnCode; //} static int cancelAsap=0; /* 0 - not yet in Cbc 1 - in Cbc with new signal handler 2 - ending Cbc */ static int statusOfCbc=0; static CoinSighandler_t saveSignal = static_cast (0); extern "C" { static void #if defined(_MSC_VER) __cdecl #endif // _MSC_VER signal_handler(int /*whichSignal*/) { cancelAsap=3; return; } } /** This is so user can trap events and do useful stuff. CbcModel model_ is available as well as anything else you care to pass in */ struct EventUserInfo { MIP_wrapper::CBUserInfo* pCbui=0; CglPreProcess* pPP=0; }; extern CglPreProcess * cbcPreProcessPointer; class MyEventHandler3 : public CbcEventHandler { public: /**@name Overrides */ //@{ virtual CbcAction event(CbcEvent whichEvent); //@} /**@name Constructors, destructor etc*/ //@{ /** Default constructor. */ MyEventHandler3(EventUserInfo& u_); /// Constructor with pointer to model (redundant as setEventHandler does) MyEventHandler3(CbcModel * model, EventUserInfo& u_); /** Destructor */ virtual ~MyEventHandler3(); /** The copy constructor. */ MyEventHandler3(const MyEventHandler3 & rhs); /// Assignment MyEventHandler3& operator=(const MyEventHandler3 & rhs); /// Clone virtual CbcEventHandler * clone() const ; //@} protected: // data goes here EventUserInfo ui; double bestSolutionValue_ = DBL_MAX; // always min }; //------------------------------------------------------------------- // Default Constructor //------------------------------------------------------------------- MyEventHandler3::MyEventHandler3 (EventUserInfo& u_) : CbcEventHandler(), ui(u_) { assert(0); } //------------------------------------------------------------------- // Copy constructor //------------------------------------------------------------------- MyEventHandler3::MyEventHandler3 (const MyEventHandler3 & rhs) : CbcEventHandler(rhs), ui(rhs.ui) { } // Constructor with pointer to model MyEventHandler3::MyEventHandler3(CbcModel * model, EventUserInfo& u_) : CbcEventHandler(model), ui(u_) { } //------------------------------------------------------------------- // Destructor //------------------------------------------------------------------- MyEventHandler3::~MyEventHandler3 () { } //---------------------------------------------------------------- // Assignment operator //------------------------------------------------------------------- MyEventHandler3 & MyEventHandler3::operator=(const MyEventHandler3& rhs) { if (this != &rhs) { CbcEventHandler::operator=(rhs); } ui = rhs.ui; return *this; } //------------------------------------------------------------------- // Clone //------------------------------------------------------------------- CbcEventHandler * MyEventHandler3::clone() const { return new MyEventHandler3(*this); } CbcEventHandler::CbcAction MyEventHandler3::event(CbcEvent whichEvent) { if(!statusOfCbc) { // override signal handler // register signal handler saveSignal = signal(SIGINT, signal_handler); statusOfCbc=1; } if ( (cancelAsap&2)!=0 ) { // printf("Cbc got cancel\n"); // switch off Clp cancel cancelAsap &= 2; return stop; } // If in sub tree carry on if (!model_->parentModel()) { if (whichEvent==endSearch&&statusOfCbc==1) { // switch off cancel cancelAsap=0; // restore signal handler signal(SIGINT, saveSignal); statusOfCbc=2; } if (whichEvent==solution||whichEvent==heuristicSolution) { // John Forrest 27.2.16: // check not duplicate if (model_->getObjValue()getObjValue(); // If preprocessing was done solution will be to processed model // int numberColumns = model_->getNumCols(); const double * bestSolution = model_->bestSolution(); assert (bestSolution); // printf("value of solution is %g\n",model_->getObjValue()); // Trying to obtain solution for the original model: assert( model_ && model_->solver() ); // double objOffset=0; // model_->solver()->getDblParam(OsiObjOffset, objOffset); double objVal = (model_->getObjValue() ); //- objOffset); John Forrest suggested to remove, 17.11.17 double bestBnd = (model_->getBestPossibleObjValue() ); //- objOffset); if ( 0!=cbcPreProcessPointer ) { if ( OsiSolverInterface* cbcPreOrig = cbcPreProcessPointer->originalModel() ) { objVal *= cbcPreOrig->getObjSense(); bestBnd *= cbcPreOrig->getObjSense(); } } else { objVal *= model_->getObjSense(); bestBnd *= model_->getObjSense(); } OsiSolverInterface* origModel=0; if ( 0!=cbcPreProcessPointer && 0!=model_->continuousSolver() ) { OsiSolverInterface * solver = (model_->continuousSolver()->clone()); // ? model_->continuousSolver()->clone() // : model_->continuousSolver()->clone(); int numberColumns = solver->getNumCols(); for (int i=0;iisInteger(i)) { solver->setColLower(i,bestSolution[i]); solver->setColUpper(i,bestSolution[i]); } } solver->resolve(); cbcPreProcessPointer->postProcess( *solver, false ); delete solver; origModel = cbcPreProcessPointer->originalModel(); ui.pCbui->pOutput->x = origModel->getColSolution(); } else { origModel = model_->solver(); ui.pCbui->pOutput->x = bestSolution; } if ( ui.pCbui->fVerb ) cerr << " % OBJ VAL RAW: " << model_->getObjValue() << " OBJ VAL ORIG(?): " << objVal << " % BND RAW: " << model_->getBestPossibleObjValue() << " BND ORIG(?): " << bestBnd // << " &prepro: " << cbcPreProcessPointer // << " &model_._solver(): " << model_->solver() << " orig NCols: " << ui.pCbui->pOutput->nCols << " prepro NCols: " << model_->getNumCols() ; assert( origModel->getNumCols() == ui.pCbui->pOutput->nCols ); if ( ui.pCbui->fVerb ) { if ( ui.pCbui->pOutput->nObjVarIndex>=0 ) cerr << " objVAR: " << ui.pCbui->pOutput->x[ui.pCbui->pOutput->nObjVarIndex]; cerr << endl; } ui.pCbui->pOutput->objVal = objVal; // origModel->getObjValue(); ui.pCbui->pOutput->status = MIP_wrapper::SAT; ui.pCbui->pOutput->statusName = "feasible from a callback"; ui.pCbui->pOutput->bestBound = bestBnd; ui.pCbui->pOutput->dWallTime = std::chrono::duration( std::chrono::steady_clock::now() - ui.pCbui->pOutput->dWallTime0).count(); ui.pCbui->pOutput->dCPUTime = model_->getCurrentSeconds(); ui.pCbui->pOutput->nNodes = model_->getNodeCount(); ui.pCbui->pOutput->nOpenNodes = -1; // model_->getNodeCount2(); /// Call the user function: if (ui.pCbui->solcbfn) { (*(ui.pCbui->solcbfn))(*(ui.pCbui->pOutput), ui.pCbui->psi); ui.pCbui->printed = true; } return noAction; // carry on } else { return noAction; // carry on } } else { return noAction; } } else { return noAction; // carry on } } /** This is so user can trap events and do useful stuff. ClpSimplex model_ is available as well as anything else you care to pass in */ class MyEventHandler4 : public ClpEventHandler { public: /**@name Overrides */ //@{ virtual int event(Event whichEvent); //@} /**@name Constructors, destructor etc*/ //@{ /** Default constructor. */ MyEventHandler4(); /// Constructor with pointer to model (redundant as setEventHandler does) MyEventHandler4(ClpSimplex * model); /** Destructor */ virtual ~MyEventHandler4(); /** The copy constructor. */ MyEventHandler4(const MyEventHandler4 & rhs); /// Assignment MyEventHandler4& operator=(const MyEventHandler4 & rhs); /// Clone virtual ClpEventHandler * clone() const ; //@} protected: // data goes here }; //------------------------------------------------------------------- // Default Constructor //------------------------------------------------------------------- MyEventHandler4::MyEventHandler4 () : ClpEventHandler() { } //------------------------------------------------------------------- // Copy constructor //------------------------------------------------------------------- MyEventHandler4::MyEventHandler4 (const MyEventHandler4 & rhs) : ClpEventHandler(rhs) { } // Constructor with pointer to model MyEventHandler4::MyEventHandler4(ClpSimplex * model) : ClpEventHandler(model) { } //------------------------------------------------------------------- // Destructor //------------------------------------------------------------------- MyEventHandler4::~MyEventHandler4 () { } //---------------------------------------------------------------- // Assignment operator //------------------------------------------------------------------- MyEventHandler4 & MyEventHandler4::operator=(const MyEventHandler4& rhs) { if (this != &rhs) { ClpEventHandler::operator=(rhs); } return *this; } //------------------------------------------------------------------- // Clone //------------------------------------------------------------------- ClpEventHandler * MyEventHandler4::clone() const { return new MyEventHandler4(*this); } int MyEventHandler4::event(Event whichEvent) { if ( (cancelAsap&1)!=0 ) { // printf("Clp got cancel\n"); return 5; } else { return -1; } } // end SolutionCallback --------------------------------------------------------------------- MIP_osicbc_wrapper::Status MIP_osicbc_wrapper::convertStatus(CbcModel *pModel) { Status s = Status::UNKNOWN; /* Converting the status. */ if (pModel->isProvenOptimal()) { s = Status::OPT; output.statusName = "Optimal"; // wrap_assert(osi., "Optimality reported but pool empty?", false); } else if (pModel->isProvenInfeasible()) { s = Status::UNSAT; output.statusName = "Infeasible"; } else if (pModel->isProvenDualInfeasible()) { s = Status::UNBND; output.statusName = "Dual infeasible"; // s = Status::UNSATorUNBND; } else if // wrong: (pModel->getColSolution()) (fabs(pModel->getObjValue()) < 1e50) { s = Status::SAT; output.statusName = "Feasible"; } else if (pModel->isAbandoned()) { // AFTER feas-ty s = Status::__ERROR; output.statusName = "Abandoned"; } else { s = Status::UNKNOWN; output.statusName = "Unknown"; } return s; } MIP_osicbc_wrapper::Status MIP_osicbc_wrapper::convertStatus() { Status s = Status::UNKNOWN; /* Converting the status. */ if (osi.isProvenOptimal()) { s = Status::OPT; output.statusName = "Optimal"; // wrap_assert(osi., "Optimality reported but pool empty?", false); } else if (osi.isProvenPrimalInfeasible()) { s = Status::UNSAT; output.statusName = "Infeasible"; } else if (osi.isProvenDualInfeasible()) { s = Status::UNBND; output.statusName = "Dual infeasible"; // s = Status::UNSATorUNBND; } else if (osi.isAbandoned()) { s = Status::__ERROR; output.statusName = "Abandoned"; } else if // wrong: (pModel->getColSolution()) (fabs(osi.getObjValue()) < osi.getInfinity()) { s = Status::SAT; output.statusName = "Feasible"; cout << " getSolverObjValue(as minim) == " << osi.getObjValue() << endl; } else { s = Status::UNKNOWN; output.statusName = "Unknown"; } return s; } void MIP_osicbc_wrapper::solve() { // Move into ancestor? if ( options->flag_all_solutions && 0==nProbType ) cerr << "WARNING. --all-solutions for SAT problems not implemented." << endl; try { /// Not using CoinPackedMatrix any more, so need to add all constraints at once: /// But this gives segf: // osi.addRows(rowStarts.size(), rowStarts.data(), // columns.data(), element.data(), rowlb.data(), rowub.data()); /// So: MIP_wrapper::addPhase1Vars(); // only now if (fVerbose) cerr << " MIP_osicbc_wrapper: adding constraints physically..." << flush; vector pRows(rowlb.size()); for (int i=0; iloadProblem(*matrix, { std::vector integer_vars; for(unsigned int i=0; isExportModel.size()) { // Not implemented for OsiClp: // osi.setColNames(colNames, 0, colObj.size(), 0); vector colN(colObj.size()); for (int j=0; jsExportModel.c_str(), 0, colN.data()); } // Tell solver to return fast if presolve or initial solve infeasible osi.getModelPtr()->setMoreSpecialOptions(3); // allow Clp to handle interrupts MyEventHandler4 clpEventHandler; osi.getModelPtr()->passInEventHandler(&clpEventHandler); /* switch on/off output to the screen */ class NullCoinMessageHandler : public CoinMessageHandler { int print() { return 0; } void checkSeverity() { } } nullHandler; // CbcSolver control(osi); // // initialize ??????? // control.fillValuesInSolver(); // CbcModel * pModel = control.model(); if ( fVerbose ) cerr << " Model creation..." << endl; // #define __USE_CbcSolver__ -- not linked rev2274 /// FOR WARMSTART for (const auto& vv: warmstart) { osi.setColName(vv.first, colNames[vv.first]); } #ifdef __USE_CbcSolver__ CbcSolver control(osi); // initialize control.fillValuesInSolver(); CbcModel& model = *control.model(); #else CbcModel model(osi); #endif // CbcSolver control(osi); // control.solve(); if ( options->absGap>=0.0 ) model.setAllowableGap( options->absGap ); if ( options->relGap>=0.0 ) model.setAllowableFractionGap( options->relGap ); if ( options->intTol>=0.0 ) model.setIntegerTolerance( options->intTol ); // model.setCutoffIncrement( objDiff ); /// WARMSTART { std::vector< std::pair< std::string, double > > mipstart; for (const auto& vv: warmstart) { mipstart.push_back( std::make_pair(colNames[vv.first], vv.second) ); } warmstart.clear(); model.setMIPStart(mipstart); } CoinMessageHandler msgStderr(stderr); class StderrCoinMessageHandler : public CoinMessageHandler { int print() { cerr << messageBuffer_ << endl; return 0; } void checkSeverity() { } } stderrHandler; if(fVerbose) { // osi.messageHandler()->setLogLevel(1); // osi.getModelPtr()->setLogLevel(1); // osi.getRealSolverPtr()->messageHandler()->setLogLevel(0); // DOES NOT WORK: TODO // model.passInMessageHandler( &stderrHandler ); msgStderr.setLogLevel( 0, 1 ); model.passInMessageHandler( &msgStderr ); // model.setLogLevel(1); // model.solver()->messageHandler()->setLogLevel(0); } else { model.passInMessageHandler(&nullHandler); model.messageHandler()->setLogLevel(0); model.setLogLevel(0); model.solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry); // osi.passInMessageHandler(&nullHandler); // osi.messageHandler()->setLogLevel(0); // osi.setHintParam(OsiDoReducePrint, true, OsiHintTry); } if(options->nTimeout != 0) { // osi.setMaximumSeconds(nTimeout); model.setMaximumSeconds(static_cast(options->nTimeout)/1000.0); } /// TODO // if(all_solutions && obj.getImpl()) { // IloNum lastObjVal = (obj.getSense() == IloObjective::Minimize ) ? // _iloosicbc->use(SolutionCallback(_iloenv, lastObjVal, *this)); // Turn off OSICBC logging /// Solution callback output.nCols = colObj.size(); // x.resize(output.nCols); // output.x = &x[0]; if (options->flag_all_solutions && cbui.solcbfn) { // Event handler. Should be after CbcMain0()? EventUserInfo ui; ui.pCbui = &cbui; // ui.pPP = 0; MyEventHandler3 eventHandler(&model, ui); model.passInEventHandler(&eventHandler); } /// Cuts needed if ( cbui.cutcbfn ) { /// This class is passed to CBC to organize cut callbacks /// We need original solutions here (combinatorial cuts) class CutCallback : public CglCutGenerator { MIP_wrapper::CBUserInfo& cbui; public: CutCallback(MIP_wrapper::CBUserInfo& ui) : cbui(ui) { } CglCutGenerator* clone() const override { return new CutCallback(cbui); } /// Make sure this overrides but we might need to compile this with old CBC as well bool needsOriginalModel() const /*override*/ { return true; } void generateCuts(const OsiSolverInterface &si, OsiCuts &cs, const CglTreeInfo info = CglTreeInfo()) override { cbui.pOutput->nCols = si.getNumCols(); MZN_ASSERT_HARD_MSG(cbui.pOutput->nCols == ((MIP_wrapper*)(cbui.wrapper))->colNames.size(), "CBC cut callback: current model is different? Ncols=" << cbui.pOutput->nCols << ", originally " << ((MIP_wrapper*)(cbui.wrapper))->colNames.size() << ". If you have an old version of CBC, to use combinatorial cuts" " run with --cbcArgs '-preprocess off'" ); cbui.pOutput->x = si.getColSolution(); // change the pointer? MIP_wrapper::CutInput cuts; cbui.cutcbfn( *cbui.pOutput, cuts, cbui.psi, info.options&128 ); // options&128: integer candidate for (const auto& cut: cuts) { // Convert cut sense OsiRowCut rc; switch (cut.sense) { case LQ: rc.setUb(cut.rhs); break; case GQ: rc.setLb(cut.rhs); break; default: assert(EQ==cut.sense); rc.setLb(cut.rhs); rc.setUb(cut.rhs); } rc.setRow(cut.rmatind.size(), cut.rmatind.data(), cut.rmatval.data()); cs.insertIfNotDuplicate(rc); } } }; CutCallback ccb(cbui); model.addCutGenerator(&ccb, 10, "MZN_cuts", true, true); // also at solution } if ( 1nThreads ) { options->cbc_cmdOptions += " -threads "; ostringstream oss; oss << options->nThreads; options->cbc_cmdOptions += oss.str(); } options->cbc_cmdOptions += " -solve"; options->cbc_cmdOptions += " -quit"; cbui.pOutput->dWallTime0 = output.dWallTime0 = std::chrono::steady_clock::now(); output.dCPUTime = clock(); /* OLD: Optimize the problem and obtain solution. */ // model.branchAndBound(); // osi.branchAndBound(); /// TAKEN FORM DRIVER3.CPP, seems to use most features: // CbcMain0(model); // CbcCbcParamUtils::setCbcModelDefaults(model) ; // const char * argv2[]={"mzn-cbc","-solve","-quit"}; // CbcMain1(3,argv2,model); #ifdef __USE_CbcSolver__ if (fVerbose) cerr << " Calling control.solve() with options '" << options->cbc_cmdOptions << "'..." << endl; control.solve (options->cbc_cmdOptions.c_str(), 1); #else #define __USE_callCbc1__ #ifdef __USE_callCbc1__ if (fVerbose) cerr << " Calling callCbc with options '" << options->cbc_cmdOptions << "'..." << endl; callCbc(options->cbc_cmdOptions, model); // callCbc1(cbc_cmdOptions, model, callBack); // What is callBack() for? TODO #else CbcMain0(model); // should be here? // // Event handler // EventUserInfo ui; // MyEventHandler3 eventHandler( &model, ui ); // model.passInEventHandler(&eventHandler); /* Now go into code for standalone solver Could copy arguments and add -quit at end to be safe but this will do */ vector argvS; MiniZinc::split(cbc_cmdOptions, argvS); vector argv; MiniZinc::vecString2vecPChar(argvS, argv); if (fVerbose) cerr << " Calling CbcMain1 with options '" << cbc_cmdOptions << "'..." << endl; CbcMain1(argv.size(),argv.data(),model,callBack); #endif #endif output.dWallTime = std::chrono::duration( std::chrono::steady_clock::now() - output.dWallTime0).count(); output.dCPUTime = (clock() - output.dCPUTime) / CLOCKS_PER_SEC; output.status = convertStatus(&model); // output.status = convertStatus(); /// Continuing to fill the output object: if (Status::OPT == output.status || Status::SAT ==output.status) { output.objVal = model.getObjValue(); // output.objVal = osi.getObjValue(); /* The size of the problem should be obtained by asking OSICBC what the actual size is, rather than using what was passed to CBCcopylp. cur_numrows and cur_numcols store the current number of rows and columns, respectively. */ // ?????????????? TODO int cur_numcols = model.getNumCols (); // int cur_numcols = osi.getNumCols (); assert(cur_numcols == colObj.size()); wrap_assert(model.getColSolution(), "Failed to get variable values."); x.assign( model.getColSolution(), model.getColSolution() + cur_numcols ); // ColSolution(); output.x = x.data(); // output.x = osi.getColSolution(); if (cbui.solcbfn && (!options->flag_all_solutions || !cbui.printed)) { cbui.solcbfn(output, cbui.psi); } } output.bestBound = model.getBestPossibleObjValue(); // output.bestBound = -1; output.nNodes = model.getNodeCount(); // output.nNodes = osi.getNodeCount(); output.nOpenNodes = -1; } catch (CoinError& err) { err.print(true); } } void MIP_osicbc_wrapper::setObjSense(int s) { osi.setObjSense(-s); } /* try the following for example: CbcMain0(model); const char * argv2[]={"driver4","-cuts","off" ,"-preprocess","off","-passc","1","-solve","-quit"}; CbcMain1(9,argv2,model); you can add any feature you want to argv2 ... if you want to add cuts yourself, or heuristics, do the following: OsiSolverInterface *solver2 = osi; CglPreProcess *process = new CglPreProcess; solver2 = process->preProcess(*solver,false,2); CbcModel model1(*solver2); model1.initialSolve(); //============================================== CglProbing generator1; generator1.setUsingObjective(true); generator1.setMaxPass(1); generator1.setMaxPassRoot(5); generator1.setMaxProbe(10); generator1.setMaxProbeRoot(1000); generator1.setMaxLook(50); generator1.setMaxLookRoot(500); generator1.setMaxElements(200); generator1.setRowCuts(3); CglGomory generator2; generator2.setLimit(300); CglKnapsackCover generator3; CglRedSplit generator4; generator4.setLimit(200); CglClique generator5; generator5.setStarCliqueReport(false); generator5.setRowCliqueReport(false); CglMixedIntegerRounding2 mixedGen; CglFlowCover flowGen; CglGMI cut1; CglMixedIntegerRounding2 cut2; CglOddHole cut3; CglSimpleRounding cut4; CglResidualCapacity cut5; CglTwomir cut6; CglZeroHalf cut7; model1.addCutGenerator(&generator1,-1,"Probing"); model1.addCutGenerator(&generator2,-1,"Gomory"); model1.addCutGenerator(&generator3,-1,"Knapsack"); model1.addCutGenerator(&generator4,-1,"RedSplit"); model1.addCutGenerator(&generator5,-1,"Clique"); model1.addCutGenerator(&flowGen,-1,"FlowCover"); model1.addCutGenerator(&mixedGen,-1,"MixedIntegerRounding"); model1.addCutGenerator(&cut1,-1,"GMI"); model1.addCutGenerator(&cut2,-1,"MixedIntegerRounding2"); model1.addCutGenerator(&cut3,-1,"OddHole"); model1.addCutGenerator(&cut4,-1,"SimpleRounding"); model1.addCutGenerator(&cut5,-1,"ResidualCapacity"); model1.addCutGenerator(&cut6,-1,"Twomir"); model1.addCutGenerator(&cut7,-1,"ZeroHalf"); CbcRounding heuristic1(model1); CbcHeuristicLocal heuristic2(model1); model1.addHeuristic(&heuristic1); model1.addHeuristic(&heuristic2); model1.setMaximumCutPassesAtRoot(50); model1.setMaximumCutPasses(1000); model1.branchAndBound(); OsiSolverInterface * solver3; process->postProcess(*model1.solver()); solver3 = solver; or, use the default strategy: CbcStrategyDefault strategy(5); model1.setStrategy(strategy); On Sun, Oct 11, 2015 at 8:38 PM, Gleb Belov wrote: Hi, I am trying to call Cbc 2.9.6 from my program. When using the tutorial-style approach OsiClpSolverInterface osi; osi.add ....... CbcModel model(osi); model.branchAndBound(); there seem to be no cuts and other stuff applied. When using the method from the examples, CbcMain0(model); const char * argv2[]={"driver4","-solve","-quit"}; CbcMain1(3,argv2,model); there are cuts applied, but obviously different (less aggressive) to the standalone Cbc executable. I also tried CbcSolver class but its method solve() is not found by the linker. So what is the 'standard' way of using the 'default' add-ons? Moreover. The attached example crashes both in the standalone Cbc and in the CbcCmain0/1 variant after a few minutes. Thanks _______________________________________________ Cbc mailing list Cbc@list.coin-or.org http://list.coin-or.org/mailman/listinfo/cbc Hi, what is currently good way to have a solution callback in Cbc? the interrupt example shows 2 ways, don't know which is right. Moreover, it says that the solution would be given for the preprocessed model. Is it possible to produce one for the original? Is it possible to call other functions from inside, such as number of nodes, dual bound? Thanks From john.forrest at fastercoin.com Thu Oct 8 10:34:15 2015 From: john.forrest at fastercoin.com (John Forrest) Date: Thu, 8 Oct 2015 15:34:15 +0100 Subject: [Cbc] Solution callbacks In-Reply-To: <5615F778.9020601@monash.edu> References: <5615F778.9020601@monash.edu> Message-ID: <56167EE7.6000607@fastercoin.com> Gleb, On 08/10/15 05:56, Gleb Belov wrote: > Hi, what is currently good way to have a solution callback in Cbc? the > interrupt example shows 2 ways, don't know which is right. > It is the event handling code you would be using. > Moreover, it says that the solution would be given for the > preprocessed model. Is it possible to produce one for the original? At present no. In principle not difficult. First the callback function would have to be modified to get passed the CglPreProcess object - easy. Then in event handler you could make a copy of object and postsolve (you need a copy as postsolve deletes data). > Is it possible to call other functions from inside, such as number of > nodes, dual bound? Yes - you have CbcModel * model_ so things like that are available (or could easily be made available) > > Thanks > John Forrest */ libminizinc-2.4.2/solvers/MIP/MIP_scip_solverfactory.cpp000066400000000000000000000006361360574160400233140ustar00rootroot00000000000000#include #include #include namespace MiniZinc { namespace { void getWrapper() { static MIP_SolverFactory _scip_solver_factory; return; } } SCIP_SolverFactoryInitialiser::SCIP_SolverFactoryInitialiser(void) { getWrapper(); } } libminizinc-2.4.2/solvers/MIP/MIP_scip_wrap.cpp000066400000000000000000000511261360574160400213630ustar00rootroot00000000000000// * -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #include #include #include #include #include using namespace std; #include #include #include "scip/scipshell.h" std::string MIP_scip_wrapper::getMznLib() { return "-Glinear_scip"; } string MIP_scip_wrapper::getDescription(MiniZinc::SolverInstanceBase::Options* opt) { ostringstream oss; oss << "MIP wrapper for SCIP " << getVersion(opt) << ". Compiled " __DATE__ " " __TIME__; return oss.str(); } string MIP_scip_wrapper::getVersion(MiniZinc::SolverInstanceBase::Options* opt) { ostringstream oss; oss << SCIPmajorVersion() << '.' << SCIPminorVersion() << '.' << SCIPtechVersion() << '.' << SCIPsubversion(); return oss.str(); } string MIP_scip_wrapper::needDllFlag( ) { return ""; } string MIP_scip_wrapper::getId() { return "scip"; } string MIP_scip_wrapper::getName() { return "SCIP"; } vector MIP_scip_wrapper::getTags() { return {"mip","float","api"}; } vector MIP_scip_wrapper::getStdFlags() { return {"-a", "-p", "-s"}; } void MIP_scip_wrapper::Options::printHelp(ostream& os) { os << "SCIP MIP wrapper options:" << std::endl // -s print statistics // << " --readParam read SCIP parameters from file // << "--writeParam write SCIP parameters to file // << "--tuneParam instruct SCIP to tune parameters instead of solving << "--writeModel write model to (.lp, .mps, ...?)" << std::endl << "-a print intermediate solutions (use for optimization problems only TODO)" << std::endl << "-p use N threads, default: 1" << std::endl // << "--nomippresolve disable MIP presolving NOT IMPL" << std::endl << "--solver-time-limit stop search after N milliseconds" << std::endl << "--workmem maximal amount of RAM used, MB" << std::endl << "--readParam read SCIP parameters from file" << std::endl << "--writeParam write SCIP parameters to file" << std::endl // << "--tuneParam instruct SCIP to tune parameters instead of solving NOT IMPL" << "--absGap absolute gap |primal-dual| to stop" << std::endl << "--relGap relative gap |primal-dual|/ to stop. Default 1e-8, set <0 to use backend's default" << std::endl << "--intTol integrality tolerance for a variable. Default 1e-8" << std::endl // << "--objDiff objective function discretization. Default 1.0" << std::endl << std::endl; } static inline bool beginswith(string s, string t) { return s.compare(0, t.length(), t)==0; } bool MIP_scip_wrapper::Options::processOption(int& i, vector& argv) { MiniZinc::CLOParser cop( i, argv ); if ( string(argv[i])=="-a" || string(argv[i])=="--all" || string(argv[i])=="--all-solutions" ) { flag_all_solutions = true; } else if (string(argv[i])=="-f") { // std::cerr << " Flag -f: ignoring fixed strategy anyway." << std::endl; } else if ( cop.get( "--writeModel", &sExportModel ) ) { } else if ( cop.get( "-p", &nThreads ) ) { } else if ( cop.get( "--solver-time-limit", &nTimeout ) ) { } else if ( cop.get( "--workmem", &nWorkMemLimit ) ) { } else if ( cop.get( "--readParam", &sReadParams ) ) { } else if ( cop.get( "--writeParam", &sWriteParams ) ) { } else if ( cop.get( "--absGap", &absGap) ) { } else if ( cop.get( "--relGap", &relGap) ) { } else if ( cop.get( "--intTol", &intTol) ) { // } else if ( cop.get( "--objDiff", &objDiff ) ) { } else return false; return true; error: return false; } void MIP_scip_wrapper::wrap_assert(SCIP_RETCODE retcode, string msg, bool fTerm) { /* evaluate return code of the SCIP process */ if( retcode != SCIP_OKAY ) { /* write error back trace */ SCIPprintError(retcode); string msgAll = (" MIP_scip_wrapper runtime error, see output: " + msg); cerr << msgAll << endl; if (fTerm) { cerr << "TERMINATING." << endl; throw runtime_error(msgAll); } } } SCIP_RETCODE MIP_scip_wrapper::openSCIP() { SCIP_CALL( SCIPcreate(&scip) ); SCIP_CALL( SCIPincludeDefaultPlugins(scip) ); /* create empty problem */ SCIP_CALL( SCIPcreateProbBasic(scip, "mzn_scip") ); return SCIP_OKAY; } SCIP_RETCODE MIP_scip_wrapper::closeSCIP() { SCIP_CALL( SCIPfree(&scip) ); /// and at last: // MIP_wrapper::cleanup(); return SCIP_OKAY; } SCIP_RETCODE MIP_scip_wrapper::doAddVars_SCIP (size_t n, double* obj, double* lb, double* ub, MIP_wrapper::VarType* vt, string *names) { /// Convert var types: // vector ctype(n); // vector pcNames(n); for (size_t j=0; j ab(nnz); for (int j=0; jub" ); setVarLB(iVar, lb); setVarUB(iVar, ub); } void MIP_scip_wrapper::setVarLB(int iVar, double lb) { auto res = SCIPchgVarLbGlobal(scip,scipVars[iVar],lb); wrap_assert( res, "scip interface: failed to set var lb." ); } void MIP_scip_wrapper::setVarUB(int iVar, double ub) { auto res = SCIPchgVarUbGlobal(scip,scipVars[iVar],ub); wrap_assert( res, "scip interface: failed to set var ub." ); } void MIP_scip_wrapper::addIndicatorConstraint( int iBVar, int bVal, int nnz, int* rmatind, double* rmatval, MIP_wrapper::LinConType sense, double rhs, string rowName) { MZN_ASSERT_HARD_MSG( 0<=bVal && 1>=bVal, "SCIP: addIndicatorConstraint: bVal not 0/1" ); //// Make sure in order to notice the indices of lazy constr: also here? TODO // ++ nRows; SCIP_CONS* cons; vector ab(nnz); SCIP_VAR* indicator_var; // SCIP 6.0.1 requires that the implication is active for indicator_x == 1 for (int j=0; j rmatvalNEG(nnz); for (int i=nnz; i--;) rmatvalNEG[i] = -rmatval[i]; wrap_assert( SCIPcreateConsBasicIndicator(scip, &cons, rowName.c_str(), indicator_var, nnz, ab.data(), rmatvalNEG.data(), -rhs ) ); wrap_assert( SCIPaddCons(scip, cons) ); wrap_assert( SCIPreleaseCons(scip, &cons) ); } } void MIP_scip_wrapper::addBoundsDisj(int n, double *fUB, double *bnd, int *vars, int nF, double *fUBF, double *bndF, int *varsF, string rowName) { SCIP_CONS* cons; std::vector v(n+nF); std::vector bt(n+nF); std::vector bs(n+nF); for (int j=0; j ab(nnz); vector nd(nnz), nr(nnz); for (int j=0; jpOutput->objVal - objVal) > 1e-12*(1.0 + fabs(objVal)) ) { newincumbent = 1; cbuiPtr->pOutput->objVal = objVal; cbuiPtr->pOutput->status = MIP_wrapper::SAT; cbuiPtr->pOutput->statusName = "feasible from a callback"; } if ( newincumbent && scipVarsPtr ) { assert(cbuiPtr->pOutput->x); SCIP_CALL( SCIPgetSolVals(scip, bestsol, cbuiPtr->pOutput->nCols, scipVarsPtr, (double*)cbuiPtr->pOutput->x) ); // wrap_assert(!retcode, "Failed to get variable values."); cbuiPtr->pOutput->nNodes = SCIPgetNNodes (scip); cbuiPtr->pOutput->nOpenNodes = SCIPgetNNodesLeft(scip); cbuiPtr->pOutput->bestBound = SCIPgetDualbound (scip); cbuiPtr->pOutput->dCPUTime = -1; /// Call the user function: if (cbuiPtr->solcbfn) (*cbuiPtr->solcbfn)(*cbuiPtr->pOutput, cbuiPtr->psi); } return SCIP_OKAY; } /** includes event handler for best solution found */ SCIP_RETCODE SCIPincludeEventHdlrBestsol( SCIP* scip /**< SCIP data structure */ ) { SCIP_EVENTHDLRDATA* eventhdlrdata; SCIP_EVENTHDLR* eventhdlr; eventhdlrdata = NULL; eventhdlr = NULL; /* create event handler for events on watched variables */ SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecBestsol, eventhdlrdata) ); assert(eventhdlr != NULL); /// Not for sub-SCIPs // SCIP_CALL( SCIPsetEventhdlrCopy(scip, eventhdlr, eventCopyBestsol) ); SCIP_CALL( SCIPsetEventhdlrInit(scip, eventhdlr, eventInitBestsol) ); SCIP_CALL( SCIPsetEventhdlrExit(scip, eventhdlr, eventExitBestsol) ); return SCIP_OKAY; } MIP_scip_wrapper::Status MIP_scip_wrapper::convertStatus(SCIP_STATUS scipStatus) { Status s = Status::UNKNOWN; /* Converting the status. */ switch(scipStatus) { case SCIP_STATUS_OPTIMAL: s = Status::OPT; output.statusName = "Optimal"; assert(SCIPgetNSolsFound(scip)); break; case SCIP_STATUS_INFEASIBLE: s = Status::UNSAT; output.statusName = "Infeasible"; break; // case SCIP_MIP_OPTIMAL_INFEAS: case SCIP_STATUS_INFORUNBD: s = Status::UNSATorUNBND; output.statusName = "Infeasible or unbounded"; break; // case SCIP_MIP_SOL_LIM: // s = Status::SAT; // wrap_assert(SCIP_getsolnpoolnumsolns(env, lp), "Feasibility reported but pool empty?", false); // break; case SCIP_STATUS_UNBOUNDED: s = Status::UNBND; output.statusName = "Unbounded"; break; // case SCIP_STATUSMIP_ABORT_INFEAS: // case SCIP_MIP_FAIL_INFEAS: // s = Status::ERROR; // break; default: // case SCIP_MIP_OPTIMAL_TOL: // case SCIP_MIP_ABORT_RELAXATION_UNBOUNDED: if (SCIPgetNSols (scip)) { s = Status::SAT; output.statusName = "Feasible"; } else { s = Status::UNKNOWN; output.statusName = "Unknown"; } } return s; } SCIP_DECL_MESSAGEWARNING(printMsg) { cerr << msg << flush; } SCIP_RETCODE MIP_scip_wrapper::solve_SCIP() { // Move into ancestor? /////////////// Last-minute solver options ////////////////// if ( options->flag_all_solutions && 0==nProbType ) cerr << "WARNING. --all-solutions for SAT problems not implemented." << endl; if (options->nThreads>0) SCIP_CALL( SCIPsetIntParam(scip, "lp/threads", options->nThreads) ); if (options->nTimeout>0) SCIP_CALL( SCIPsetRealParam(scip, "limits/time", static_cast(options->nTimeout)/1000.0) ); if (options->nWorkMemLimit>0) SCIP_CALL( SCIPsetRealParam(scip, "limits/memory", options->nWorkMemLimit) ); if ( options->absGap>=0.0 ) SCIP_CALL( SCIPsetRealParam( scip, "limits/absgap", options->absGap ) ); if ( options->relGap>=0.0 ) SCIP_CALL( SCIPsetRealParam( scip, "limits/gap", options->relGap ) ); if ( options->intTol>=0.0 ) SCIP_CALL( SCIPsetRealParam( scip, "numerics/feastol", options->intTol ) ); // retcode = SCIP_setintparam (env, SCIP_PARAM_ClockType, 1); // CPU time // wrap_assert(!retcode, " SCIP Warning: Failure to measure CPU time.", false); if (!options->sExportModel.empty()) { // std::cerr <<" Exporting LP model to " << sExportModel << " ..." << std::endl; SCIP_CALL( SCIPwriteOrigProblem(scip, options->sExportModel.c_str(), 0, 0) ); } /* Turn on output to the screen - after model export */ if(!fVerbose) { // SCIP_CALL(SCIPsetMessagehdlr(scip, NULL)); No LP export then SCIPsetMessagehdlrQuiet(scip, true); } else { SCIP_MESSAGEHDLR* pHndl=0; SCIP_CALL ( SCIPmessagehdlrCreate ( &pHndl, FALSE, NULL, FALSE, printMsg, printMsg, printMsg, NULL, NULL) ); SCIP_CALL ( SCIPsetMessagehdlr(scip, pHndl) ); } // assert(scipVars.size() == colObj.size()); int cur_numcols = scipVars.size(); // No, we create negated indicators: getNCols(); assert(cur_numcols == colObj.size()); assert(cur_numcols == scipVars.size()); /// Solution callback output.nCols = colObj.size(); x.resize(output.nCols); output.x = &x[0]; if (options->flag_all_solutions && cbui.solcbfn && !cbuiPtr) { /* include event handler for best solution found */ SCIP_CALL( SCIPincludeEventHdlrBestsol(scip) ); cbuiPtr = &cbui; // not thread-safe... TODO scipVarsPtr = &scipVars[0]; // retcode = SCIP_setinfocallbackfunc (env, solcallback, &cbui); // wrap_assert(!retcode, "Failed to set solution callback", false); } if (options->sReadParams.size()) { SCIP_CALL( SCIPreadParams (scip, options->sReadParams.c_str()) ); } if (options->sWriteParams.size()) { SCIP_CALL( SCIPwriteParams (scip, options->sReadParams.c_str(), TRUE, FALSE) ); } cbui.pOutput->dWallTime0 = output.dWallTime0 = std::chrono::steady_clock::now(); output.dCPUTime = clock(); /* Optimize the problem and obtain solution. */ SCIP_CALL( SCIPsolve (scip) ); // wrap_assert( !retcode, "Failed to optimize MIP." ); output.dWallTime = std::chrono::duration( std::chrono::steady_clock::now() - output.dWallTime0).count(); output.dCPUTime = (clock() - output.dCPUTime) / CLOCKS_PER_SEC; cbuiPtr = 0; /// cleanup scipVarsPtr = 0; SCIP_STATUS solstat = SCIPgetStatus (scip); output.status = convertStatus(solstat); // output.statusName = SCIP_getstatstring (env, solstat, scip_status_buffer); /// Continuing to fill the output object: output.objVal = SCIPgetPrimalbound (scip); output.bestBound = SCIPgetDualbound (scip); // wrap_assert(!retcode, "Failed to get the best bound.", false); if (Status::OPT == output.status || Status::SAT ==output.status) { // wrap_assert( !retcode, "No MIP objective value available." ); x.resize(cur_numcols); output.x = &x[0]; SCIP_CALL( SCIPgetSolVals(scip, SCIPgetBestSol(scip), cur_numcols, &scipVars[0], (double*)output.x) ); if (cbui.solcbfn && (!options->flag_all_solutions || !cbui.printed)) { cbui.solcbfn(output, cbui.psi); } } output.nNodes = SCIPgetNNodes (scip); output.nOpenNodes = SCIPgetNNodesLeft(scip); // SCIP_getnodeleftcnt (env, lp); SCIP_CALL( SCIPfreeTransform(scip) ); return SCIP_OKAY; } SCIP_RETCODE MIP_scip_wrapper::setObjSense_SCIP(int s) { SCIP_CALL(SCIPsetObjsense(scip, s>0 ? SCIP_OBJSENSE_MAXIMIZE : SCIP_OBJSENSE_MINIMIZE)); return SCIP_OKAY; } libminizinc-2.4.2/solvers/MIP/MIP_solverinstance.cpp000066400000000000000000000140661360574160400224350ustar00rootroot00000000000000// * -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was ! distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* This is the main file for a mzn-cplex solver using a unified * linearization module && a flexible flattener-to-solver interface */ /// TODO Quadratic terms, even CBC #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #include #include #include using namespace std; #include #include std::string MIP_wrapper::getMznLib() { return "-Glinear"; } namespace MiniZinc { namespace SCIPConstraints { bool CheckAnnUserCut(const Call* call) { if(!call->ann().isEmpty()) { if(call->ann().contains(constants().ann.user_cut)) { return true; } } return false; } bool CheckAnnLazyConstraint(const Call* call) { if(!call->ann().isEmpty()) { if(call->ann().contains(constants().ann.lazy_constraint)) { return true; } } return false; } int GetMaskConsType(const Call* call) { int mask=0; const bool fUC = CheckAnnUserCut(call); const bool fLC = CheckAnnLazyConstraint(call); if (fUC) { mask |= MIP_wrapper::MaskConsType_Usercut; } if (fLC) { mask |= MIP_wrapper::MaskConsType_Lazy; } if (!fUC && !fLC) mask |= MIP_wrapper::MaskConsType_Normal; return mask; // return MIP_wrapper::MaskConsType_Normal; // recognition fails } } } using namespace MiniZinc; void XBZCutGen::generate(const MIP_wrapper::Output& slvOut, MIP_wrapper::CutInput& cutsIn) { assert( pMIP ); const int n = static_cast(varX.size()); assert( n==varB.size() ); MIP_wrapper::CutDef cut( MIP_wrapper::GQ, MIP_wrapper::MaskConsType_Usercut ); cut.addVar( varZ, -1.0 ); for ( int i=0; i=0 && ix=0 && ibcolLB[ ix ]; const double UBXi = pMIP->colUB[ ix ]; // tighter bounds from presolve? TODO bool fi = ( theXi + LBXi * ( theBi - 1.0 ) - UBXi * theBi < 0.0 ); if ( fi ) { cut.addVar( ix, 1.0 ); cut.addVar( ib, LBXi ); cut.rhs += LBXi; } else { cut.addVar( ib, UBXi ); } } double dViol = cut.computeViol( slvOut.x, slvOut.nCols ); if ( dViol > 0.01 ) { // ?? PARAM? TODO cutsIn.push_back( cut ); cerr << " vi" << dViol << flush; // cout << cut.rmatind.size() << ' ' // << cut.rhs << " cutlen, rhs. (Sense fixed to GQ) " << endl; // for ( int i=0; icolUB[varXij[i*nN+i]] > 0.0) oss << "SECutGen with " << nN << " cities: diagonal flow " << (i+1) << " has UB=" << pMIP->colUB[varXij[i*nN+i]] << "\n"; return oss.str(); } void SECCutGen::generate(const MIP_wrapper::Output& slvOut, MIP_wrapper::CutInput& cutsIn) { assert( pMIP ); /// Extract graph, converting to undirected typedef map< pair< int, int >, double > TMapFlow; TMapFlow mapFlow; for ( int i=0; i fabs(xij), "circuit: X[" << (i+1) << ", " << (j+1) << "]==" << xij ); MZN_ASSERT_HARD_MSG( -1e-4 < xij && 1.0+1e-4 > xij, // adjusted from 1e-6 to 1e-4 for CBC. 7.8.19 "circuit: X[" << (i+1) << ", " << (j+1) << "]==" << xij ); if ( 1e-4 <= xij ) { mapFlow[ make_pair( min(i,j), max(i,j) ) ] += xij; } } } /// Invoking Min Cut // cerr << " MIN CUT... " << flush; Algorithms::MinCut mc; mc.nNodes = nN; mc.edges.reserve( mapFlow.size() ); mc.weights.reserve( mapFlow.size() ); for ( const auto& mf: mapFlow ) { mc.edges.push_back( mf.first ); mc.weights.push_back( mf.second ); } mc.solve(); /// Check if violation if ( mc.wMinCut <= 1.999 ) { MIP_wrapper::CutDef cut( MIP_wrapper::GQ, MIP_wrapper::MaskConsType_Lazy | MIP_wrapper::MaskConsType_Usercut ); cut.rhs = 1.0; int nCutSize=0; constexpr int nElemPrint = 20; // cerr << " CUT: [ "; for ( int i=0; i 0.0001 ) { // ?? PARAM? TODO. See also min cut value required cutsIn.push_back( cut ); /* cerr << " SEC: viol=" << dViol << " N NODES: " << nN << " |X|: : " << nCutSize << flush; */ } else { MZN_ASSERT_HARD_MSG( 0, " SEC cut: N nodes = " << nN << ": violation = " << dViol << ": too small compared to the min-cut value " << (2.0-mc.wMinCut) ); } } } void SECCutGen::print(ostream&) { } libminizinc-2.4.2/solvers/MIP/MIP_wrap.cpp000066400000000000000000000011101360574160400203310ustar00rootroot00000000000000// * -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Gleb Belov */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #include #include #include using namespace std; #include libminizinc-2.4.2/solvers/MIP/MIP_xpress_solverfactory.cpp000066400000000000000000000006521360574160400237000ustar00rootroot00000000000000#include #include #include namespace MiniZinc { namespace { void getWrapper() { static MIP_SolverFactory _xpress_solver_factory; return; } } Xpress_SolverFactoryInitialiser::Xpress_SolverFactoryInitialiser(void) { getWrapper(); } } libminizinc-2.4.2/solvers/MIP/MIP_xpress_wrap.cpp000066400000000000000000000264051360574160400217530ustar00rootroot00000000000000/* * main authors: * Karsten Lehmann */ /* this source code form is subject to the terms of the mozilla public * license, v. 2.0. if a copy of the mpl was not distributed with this * file, you can obtain one at http://mozilla.org/mpl/2.0/. */ #include #include #include #include #include #include #include #include #include #include "minizinc/config.hh" #include "minizinc/exception.hh" #include "minizinc/solvers/MIP/MIP_xpress_wrap.hh" #include "minizinc/utils.hh" struct UserSolutionCallbackData { MIP_wrapper::CBUserInfo *info; XPRBprob *problem; vector *variables; }; class XpressException : public runtime_error { public: XpressException(string msg) : runtime_error(" MIP_xpress_wrapper: " + msg) {} }; string MIP_xpress_wrapper::getDescription(MiniZinc::SolverInstanceBase::Options* opt) { char v[16]; XPRSgetversion(v); ostringstream oss; oss << " MIP wrapper for FICO Xpress Optimiser version " << v; oss << ". Compiled " __DATE__ " " __TIME__; return oss.str(); } string MIP_xpress_wrapper::getVersion(MiniZinc::SolverInstanceBase::Options* opt) { char v[16]; XPRSgetversion(v); return v; } string MIP_xpress_wrapper::needDllFlag( ) { return ""; } string MIP_xpress_wrapper::getId() { return "xpress"; } string MIP_xpress_wrapper::getName() { return "Xpress"; } vector MIP_xpress_wrapper::getTags() { return {"mip","float","api"}; } vector MIP_xpress_wrapper::getStdFlags() { return {"-a", "-n", "-s"}; } void MIP_xpress_wrapper::Options::printHelp(ostream &os) { os << "XPRESS MIP wrapper options:" << std::endl << "--msgLevel print solver output, default: 0" << std::endl << "--logFile log file" << std::endl << "--solver-time-limit stop search after N milliseconds, if negative, it " "will only stop if at least one solution was found" << std::endl << "-n , --numSolutions stop search after N solutions" << std::endl << "--writeModel write model to " << std::endl << "--writeModelFormat [lp|mps] the file format of the written model(lp " "or mps), default: lp" << std::endl << "--absGap absolute gap |primal-dual| to stop, default: " << 0 << std::endl << "--relGap relative gap |primal-dual|/ to stop, " "default: " << 0.0001 << std::endl << "-a, --printAllSolutions print intermediate solution, default: false" << std::endl << std::endl; } bool MIP_xpress_wrapper::Options::processOption(int &i, std::vector& argv) { MiniZinc::CLOParser cop(i, argv); if (cop.get("--msgLevel", &msgLevel)) { } else if (cop.get("--logFile", &logFile)) { } else if (cop.get("--solver-time-limit", &timeout)) { } else if (cop.get("-n --numSolutions", &numSolutions)) { } else if (cop.get("--writeModel", &writeModelFile)) { } else if (cop.get("--writeModelFormat", &writeModelFormat)) { } else if (cop.get("--relGap", &relGap)) { } else if (cop.get("--absGap", &absGap)) { } else if (string(argv[i]) == "--printAllSolutions" || string(argv[i]) == "-a") { printAllSolutions = true; } else return false; return true; } void MIP_xpress_wrapper::setOptions() { XPRSprob xprsProblem = problem.getXPRSprob(); problem.setMsgLevel(options->msgLevel); XPRSsetlogfile(xprsProblem, options->logFile.c_str()); if (options->timeout > 1000 || options->timeout < -1000) { XPRSsetintcontrol(xprsProblem, XPRS_MAXTIME, static_cast(options->timeout / 1000)); } XPRSsetintcontrol(xprsProblem, XPRS_MAXMIPSOL, options->numSolutions); XPRSsetdblcontrol(xprsProblem, XPRS_MIPABSSTOP, options->absGap); XPRSsetdblcontrol(xprsProblem, XPRS_MIPRELSTOP, options->relGap); } static MIP_wrapper::Status convertStatus(int xpressStatus) { switch (xpressStatus) { case XPRB_MIP_OPTIMAL: return MIP_wrapper::Status::OPT; case XPRB_MIP_INFEAS: return MIP_wrapper::Status::UNSAT; case XPRB_MIP_UNBOUNDED: return MIP_wrapper::Status::UNBND; case XPRB_MIP_NO_SOL_FOUND: return MIP_wrapper::Status::UNKNOWN; case XPRB_MIP_NOT_LOADED: return MIP_wrapper::Status::__ERROR; default: return MIP_wrapper::Status::UNKNOWN; } } static string getStatusName(int xpressStatus) { string rt = "Xpress stopped with status: "; switch (xpressStatus) { case XPRB_MIP_OPTIMAL: return rt + "Optimal"; case XPRB_MIP_INFEAS: return rt + "Infeasible"; case XPRB_MIP_UNBOUNDED: return rt + "Unbounded"; case XPRB_MIP_NO_SOL_FOUND: return rt + "No solution found"; case XPRB_MIP_NOT_LOADED: return rt + "No problem loaded or error"; default: return rt + "Unknown status"; } } static void setOutputVariables(MIP_xpress_wrapper::Output *output, vector *variables) { size_t nCols = variables->size(); double *x = (double *)malloc(nCols * sizeof(double)); for (size_t ii = 0; ii < nCols; ii++) { x[ii] = (*variables)[ii].getSol(); } output->x = x; } static void setOutputAttributes(MIP_xpress_wrapper::Output *output, XPRSprob xprsProblem) { int xpressStatus = 0; XPRSgetintattrib(xprsProblem, XPRS_MIPSTATUS, &xpressStatus); output->status = convertStatus(xpressStatus); output->statusName = getStatusName(xpressStatus); XPRSgetdblattrib(xprsProblem, XPRS_MIPOBJVAL, &output->objVal); XPRSgetdblattrib(xprsProblem, XPRS_BESTBOUND, &output->bestBound); XPRSgetintattrib(xprsProblem, XPRS_NODES, &output->nNodes); XPRSgetintattrib(xprsProblem, XPRS_ACTIVENODES, &output->nOpenNodes); output->dWallTime = std::chrono::duration( std::chrono::steady_clock::now() - output->dWallTime0) .count(); output->dCPUTime = double(std::clock() - output->cCPUTime0) / CLOCKS_PER_SEC; } static void XPRS_CC userSolNotifyCallback(XPRSprob xprsProblem, void *userData) { UserSolutionCallbackData *data = (UserSolutionCallbackData *)userData; MIP_wrapper::CBUserInfo *info = data->info; setOutputAttributes(info->pOutput, xprsProblem); data->problem->beginCB(xprsProblem); data->problem->sync(XPRB_XPRS_SOL); setOutputVariables(info->pOutput, data->variables); data->problem->endCB(); if (info->solcbfn) { (*info->solcbfn)(*info->pOutput, info->ppp); } } void MIP_xpress_wrapper::doAddVars(size_t n, double *obj, double *lb, double *ub, VarType *vt, string *names) { if (obj == nullptr || lb == nullptr || ub == nullptr || vt == nullptr || names == nullptr) { throw XpressException("invalid input"); } for (size_t i = 0; i < n; ++i) { char *var_name = (char *)names[i].c_str(); int var_type = convertVariableType(vt[i]); XPRBvar var = problem.newVar(var_name, var_type, lb[i], ub[i]); variables.push_back(var); xpressObj.setTerm(obj[i], var); } } void MIP_xpress_wrapper::addRow(int nnz, int *rmatind, double *rmatval, LinConType sense, double rhs, int mask, string rowName) { addConstraint(nnz, rmatind, rmatval, sense, rhs, mask, rowName); } XPRBctr MIP_xpress_wrapper::addConstraint(int nnz, int *rmatind, double *rmatval, LinConType sense, double rhs, int mask, string rowName) { nRows++; XPRBctr constraint = problem.newCtr(rowName.c_str()); for (int i = 0; i < nnz; ++i) { constraint.setTerm(variables[rmatind[i]], rmatval[i]); } constraint.setTerm(rhs); if (constraint.setType(convertConstraintType(sense)) == 1) { throw XpressException("error while setting sense of constraint"); } return constraint; } void MIP_xpress_wrapper::writeModelIfRequested() { int format = XPRB_LP; if (options->writeModelFormat == "lp") { format = XPRB_LP; } else if (options->writeModelFormat == "mps") { format = XPRB_MPS; } if (!options->writeModelFile.empty()) { problem.exportProb(format, options->writeModelFile.c_str()); } } void MIP_xpress_wrapper::addDummyConstraint() { if (getNCols() == 0) { return; } XPRBctr constraint = problem.newCtr("dummy_constraint"); constraint.setTerm(variables[0], 1); constraint.setType(convertConstraintType(LinConType::LQ)); constraint.setTerm(variables[0].getUB()); } void MIP_xpress_wrapper::solve() { if (getNRows() == 0) { addDummyConstraint(); } setOptions(); writeModelIfRequested(); setUserSolutionCallback(); problem.setObj(xpressObj); cbui.pOutput->dWallTime0 = output.dWallTime0 = std::chrono::steady_clock::now(); cbui.pOutput->cCPUTime0 = output.dCPUTime = std::clock(); if (problem.mipOptimize("c") == 1) { throw XpressException("error while solving"); } setOutputVariables(&output, &variables); setOutputAttributes(&output, problem.getXPRSprob()); if ( !options->printAllSolutions && cbui.solcbfn) { cbui.solcbfn(output, cbui.ppp); } } void MIP_xpress_wrapper::setUserSolutionCallback() { if (!options->printAllSolutions) { return; } UserSolutionCallbackData *data = new UserSolutionCallbackData{&cbui, &problem, &variables}; XPRSsetcbintsol(problem.getXPRSprob(), userSolNotifyCallback, data); } void MIP_xpress_wrapper::setObjSense(int s) { problem.setSense(convertObjectiveSense(s)); } void MIP_xpress_wrapper::setVarLB(int iVar, double lb) { variables[iVar].setLB(lb); } void MIP_xpress_wrapper::setVarUB(int iVar, double ub) { variables[iVar].setUB(ub); } void MIP_xpress_wrapper::setVarBounds(int iVar, double lb, double ub) { setVarLB(iVar, lb); setVarUB(iVar, ub); } void MIP_xpress_wrapper::addIndicatorConstraint(int iBVar, int bVal, int nnz, int *rmatind, double *rmatval, LinConType sense, double rhs, string rowName) { if (bVal != 0 && bVal != 1) { throw XpressException("indicator bval not in 0/1"); } XPRBctr constraint = addConstraint(nnz, rmatind, rmatval, sense, rhs, 0, rowName); constraint.setIndicator(2 * bVal - 1, variables[iBVar]); } bool MIP_xpress_wrapper::addWarmStart(const std::vector &vars, const std::vector vals) { XPRBsol warmstart = problem.newSol(); for (size_t ii = 0; ii < vars.size(); ii++) { warmstart.setVar(variables[vars[ii]], vals[ii]); } return 1 - problem.addMIPSol(warmstart); } int MIP_xpress_wrapper::convertConstraintType(LinConType sense) { switch (sense) { case MIP_wrapper::LQ: return XPRB_L; case MIP_wrapper::EQ: return XPRB_E; case MIP_wrapper::GQ: return XPRB_G; default: throw XpressException("unkown constraint sense"); } } int MIP_xpress_wrapper::convertVariableType(VarType varType) { switch (varType) { case REAL: return XPRB_PL; case INT: return XPRB_UI; case BINARY: return XPRB_BV; default: throw XpressException("unknown variable type"); } } int MIP_xpress_wrapper::convertObjectiveSense(int s) { switch (s) { case 1: return XPRB_MAXIM; case -1: return XPRB_MINIM; default: throw XpressException("unknown objective sense"); } } libminizinc-2.4.2/solvers/fzn/000077500000000000000000000000001360574160400163265ustar00rootroot00000000000000libminizinc-2.4.2/solvers/fzn/fzn_solverfactory.cpp000066400000000000000000000005101360574160400226050ustar00rootroot00000000000000#include #include namespace MiniZinc { namespace { void getWrapper() { static FZN_SolverFactory _fzn_solverfactory; return; } } FZN_SolverFactoryInitialiser::FZN_SolverFactoryInitialiser(void) { getWrapper(); } } libminizinc-2.4.2/solvers/fzn/fzn_solverinstance.cpp000066400000000000000000000245331360574160400227550ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #endif #ifdef _WIN32 #define NOMINMAX // Need this before all (implicit) include's of Windows.h #endif #include #include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #undef ERROR #endif using namespace std; namespace MiniZinc { FZN_SolverFactory::FZN_SolverFactory(void) { SolverConfig sc("org.minizinc.mzn-fzn",MZN_VERSION_MAJOR "." MZN_VERSION_MINOR "." MZN_VERSION_PATCH); sc.name("Generic FlatZinc driver"); sc.mznlibVersion(1); sc.description("MiniZinc generic FlatZinc solver plugin"); sc.requiredFlags({"--fzn-cmd"}); sc.stdFlags({"-a","-n","-f","-p","-s","-r","-v"}); sc.tags({"__internal__"}); SolverConfigs::registerBuiltinSolver(sc); } string FZN_SolverFactory::getDescription(SolverInstanceBase::Options*) { string v = "FZN solver plugin, compiled " __DATE__ " " __TIME__; return v; } string FZN_SolverFactory::getVersion(SolverInstanceBase::Options*) { return MZN_VERSION_MAJOR; } string FZN_SolverFactory::getId() { return "org.minizinc.mzn-fzn"; } void FZN_SolverFactory::printHelp(ostream& os) { os << "MZN-FZN plugin options:" << std::endl << " --fzn-cmd , --flatzinc-cmd \n the backend solver filename.\n" << " -b, --backend, --solver-backend \n the backend codename. Currently passed to the solver.\n" << " --fzn-flags , --flatzinc-flags \n Specify option to be passed to the FlatZinc interpreter.\n" << " --fzn-flag